题意:求两个字符串的最长公共子串
分析:做法是构造新的串是两个串连接而成,中间用没有出现的字符隔开(因为这样才能保证S的后缀的公共前缀不会跨出一个原有串的范围),即newS = S + '$' + T。对其求sa数组和height数组,取最小值的height[i],且两个后缀串属于不同的字符串。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> typedef long long ll; const int N = 1e4 + 5; std::string t, str; int sa[N<<1], rank[N<<1]; int height[N<<1]; int tmp[N<<1]; int n, k; bool cmp_sa(int i, int j) { if (rank[i] != rank[j]) { return rank[i] < rank[j]; } else { int ri = i + k <= n ? rank[i+k] : -1; int rj = j + k <= n ? rank[j+k] : -1; return ri < rj; } } void get_sa(std::string S, int *sa) { n = S.length (); for (int i=0; i<=n; ++i) { sa[i] = i; rank[i] = i < n ? (int) S[i] : -1; } for (k=1; k<=n; k<<=1) { std::sort (sa, sa+n+1, cmp_sa); tmp[sa[0]] = 0; for (int i=1; i<=n; ++i) { tmp[sa[i]] = tmp[sa[i-1]] + (cmp_sa (sa[i-1], sa[i]) ? 1 : 0); } for (int i=0; i<=n; ++i) { rank[i] = tmp[i]; } } } void get_height(std::string S, int *sa, int *height) { int n = S.length (); for (int i=0; i<n; ++i) { rank[sa[i]] = i; } int h = 0; height[0] = 0; for (int i=0; i<n; ++i) { int j = sa[rank[i]-1]; if (h > 0) { h--; } for (; j+h<n && i+h<n; h++) { if (S[j+h] != S[i+h]) { break; } } height[rank[i]-1] = h; } } int run(int len1, std::string S) { get_sa (S, sa); get_height (S, sa, height); int ret = 0; for (int i=0; i<S.length (); ++i) { if ((sa[i]<len1) != (sa[i+1]<len1)) { ret = std::max (ret, height[i]); } } return ret; } int main() { int T; scanf ("%d", &T); getchar (); while (T--) { getline (std::cin, t); str = t; int len1 = t.length (); getline (std::cin, t); str += '$' + t; int ans = run (len1, str); printf ("Nejdelsi spolecny retezec ma delku %d. ", ans); } return 0; }