POJ 2217: Secretary
蟻本ツアーです。これ KMP(table を作る部分) で解けそうですがせっかくなので suffix array で解きました。
解法
S += T とやって2つの文字を合体させた後, lcp テーブルを作ります。で, S の前半側と S の後半側で一致する文字数を lcp で調べます。
const int MAXN = 20010; namespace SA { int rank[MAXN], tmp[MAXN]; int n, k; bool compare_sa(int i, int j) { if (rank[i] != rank[j]) return rank[i] < rank[j]; int ri = (i+k <= n) ? rank[i+k] : -1; int rj = (j+k <= n) ? rank[j+k] : -1; return ri < rj; } // suffix array を構築する // O(N log^2 N) // how to use: construct_saを呼ぶとsa配列にSuffixArrayを構築する void createSA(const string& s, int* sa) { n = s.size(); // 最初は 1 文字ソート for (int i = 0; i <= n; i++) { sa[i] = i; rank[i] = i < n ? s[i] : -1; } for (k = 1; k <= n; k*=2) { sort(sa, sa+n+1, compare_sa); tmp[sa[0]] = 0; for (int i = 1; i <= n; i++) { tmp[sa[i]] = tmp[sa[i-1]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0); } for (int i = 0; i <= n; i++) rank[i] = tmp[i]; } } namespace LCP { int rank[MAXN]; // suffix array の情報をもとに longest common prefix を構築する // O(N) // hot to use: construct_lcpに文字列と suffix array の情報を入れると lcp 配列を作る void createLCP(const string& s, const int* sa, int* lcp) { int n = s.size(); for (int i = 0; i <= n; i++) rank[sa[i]] = i; int h = 0; lcp[0] = 0; for (int i = 0; i < n; i++) { int j = sa[rank[i]-1]; h = max(0, h-1); for (; j+h < n && i+h < n; h++) { if (s[j+h] != s[i+h]) break; } lcp[rank[i]-1] = h; } } } // namespace LCP } // namespace SA char str[MAXN]; void getInput(string& s) { fgets(str, MAXN, stdin); strtok(str, "\n\0"); s = str; } int sa[MAXN], lcp[MAXN]; int main() { int T; scanf("%d\n", &T); while (T--) { string S, T; getInput(S); getInput(T); int n = S.size(), m = T.size(); S += '\n'; S += T; SA::createSA(S, sa); SA::LCP::createLCP(S, sa, lcp); int nm = S.size(), ans = 0; for (int i = 0; i < nm; i++) { if (sa[i] < n && sa[i+1] < n) continue; if (sa[i] > n && sa[i+1] > n) continue; ans = max(ans, lcp[i]); } printf("Nejdelsi spolecny retezec ma delku %d.\n", ans); } return 0; }