http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4629
后缀数组或扩展kmp
SA做法
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <ctime> #include <bitset> #include <iomanip> #pragma comment(linker, "/STACK:102400000,102400000") using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::stringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; using std::unique; using std::lower_bound; using std::random_shuffle; using std::bitset; using std::upper_bound; using std::multiset; using std::ios; using std::make_heap; using std::push_heap; using std::pop_heap; typedef long long LL; typedef unsigned long long ULL; typedef unsigned UN; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; typedef long double LF; const int MAXN(200010); const int MAXM(20010); const int MAXE(2100010); const int MAXK(6); const int HSIZE(1313131); const int SIGMA_SIZE(26); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const ULL BASE(31); const LL LIM(1e13); const int INV(-10000); const int MOD(1000000007); const double EPS(1e-7); const LF PI(acos(-1.0)); template<typename T> inline bool checkmax(T &a, T b){if(b > a) { a = b; return true;} return false;} template<typename T> inline bool checkmin(T &a, T b){if(b < a) { a = b; return true;} return false;} template<typename T> inline T ABS(T a){return a < 0? -a: a;} template<typename T> inline bool EZ(T a){return ABS(a) < EPS;} int Log[MAXN]; void initLog(){ Log[0] = -1; for(int i = 1; i < MAXN; ++i) Log[i] = (i&(i-1))? Log[i-1]: Log[i-1]+1; } struct SA{ char S[MAXN]; int sa[MAXN], t1[MAXN], t2[MAXN], cnt[MAXN], len, M; void init(int l, int m = 128){ len = l; M = m; int *p1 = t1, *p2 = t2; for(int i = 0; i < M; ++i) cnt[i] = 0; for(int i = 0; i <= len; ++i) ++cnt[p1[i] = S[i]]; for(int i = 1; i < M; ++i) cnt[i] += cnt[i-1]; for(int i = len; i >= 0; --i) sa[--cnt[p1[i]]] = i; int temp = 1; for(int k = 1; temp <= len; k <<= 1){ temp = 0; for(int i = len-k+1; i <= len; ++i) p2[temp++] = i; for(int i = 0; i <= len; ++i) if(sa[i] >= k) p2[temp++] = sa[i]-k; for(int i = 0; i < M; ++i) cnt[i] = 0; for(int i = 0; i <= len; ++i) ++cnt[p1[p2[i]]]; for(int i = 1; i < M; ++i) cnt[i] += cnt[i-1]; for(int i = len; i >= 0; --i) sa[--cnt[p1[p2[i]]]] = p2[i]; swap(p1, p2); temp = 1; p1[sa[0]] = 0; for(int i = 1; i <= len; ++i) p1[sa[i]] = p2[sa[i-1]] == p2[sa[i]] && p2[sa[i-1]+k] == p2[sa[i]+k]? temp-1: temp++; M = temp; } } int rank[MAXN], hei[MAXN]; void getHei(){ int k = 0; for(int i = 0; i <= len; ++i) rank[sa[i]] = i; for(int i = 0; i < len; ++i){ if(k) --k; int j = sa[rank[i]-1]; while(S[i+k] == S[j+k]) ++k; hei[rank[i]] = k; } } int dp[MAXH][MAXN]; void initRMQ(){ for(int i = 1; i <= len; ++i) dp[0][i] = hei[i]; for(int i = 1; (1 << i) <= len; ++i) for(int j = 1; j+(1 << i)-1 <= len; ++j) dp[i][j] = min(dp[i-1][j], dp[i-1][j+(1 << (i-1))]); } int lcp(int a, int b){ if(a == b) return len-a; if(a == len || b == len) return 0; a = rank[a]; b = rank[b]; if(a > b) swap(a, b); ++a; int temp = Log[b-a+1]; return min(dp[temp][a], dp[temp][b-(1 << temp)+1]); } int solve(int ind, int lim){ ind = rank[ind]; int ret = 0; int l = 0, r = ind; while(l < r){ int m = (l+r) >> 1; if(lcp(sa[m], sa[ind]) >= lim) r = m; else l = m+1; } ret += ind-l+1; l = ind, r = len+1; while(l < r){ int m = (l+r) >> 1; if(lcp(sa[m], sa[ind]) >= lim) l = m+1; else r = m; } --l; ret += l-ind+1; --ret; return ret; } } sa1, sa2; int main(){ initLog(); int TC; scanf("%d", &TC); while(TC--){ scanf("%s%s", sa1.S, sa2.S); int len1 = strlen(sa1.S), len2 = strlen(sa2.S); sa1.S[len1] = 1; strcpy(sa1.S+len1+1, sa2.S); sa1.init(len1+len2+1); sa2.init(len2); sa1.getHei(); sa2.getHei(); sa1.initRMQ(); sa2.initRMQ(); LL ans = 0; for(int i = 1; i < len2; ++i){ LL t1 = sa1.solve(len1+1, i); LL t2 = sa2.solve(0, i); LL t3 = t1-t2; t1 = sa1.solve(len1+1+i, len2-i); t2 = sa2.solve(i, len2-i); ans += t3*(t1-t2); } printf("%lld\n", ans); } return 0; }
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <ctime> #include <bitset> #include <iomanip> #pragma comment(linker, "/STACK:102400000,102400000") using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::stringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; using std::unique; using std::lower_bound; using std::random_shuffle; using std::bitset; using std::upper_bound; using std::multiset; using std::ios; using std::make_heap; using std::push_heap; using std::pop_heap; typedef long long LL; typedef unsigned long long ULL; typedef unsigned UN; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; typedef long double LF; const int MAXN(100010); const int MAXM(20010); const int MAXE(2100010); const int MAXK(6); const int HSIZE(1313131); const int SIGMA_SIZE(26); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const ULL BASE(31); const LL LIM(1e13); const int INV(-10000); const int MOD(1000000007); const double EPS(1e-7); const LF PI(acos(-1.0)); template<typename T> inline bool checkmax(T &a, T b){if(b > a) { a = b; return true;} return false;} template<typename T> inline bool checkmin(T &a, T b){if(b < a) { a = b; return true;} return false;} template<typename T> inline T ABS(T a){return a < 0? -a: a;} template<typename T> inline bool EZ(T a){return ABS(a) < EPS;} /* template<typename TY, int N> struct EXKMP{ TY P[N]; int lenp; int next[N]; void getnext(){ next[0] = lenp; int k = 1, l = 0, a = 1; while(k < lenp && P[k] == P[l]){ ++k; ++l; } next[l] = 1; int i = 2; while(i < lenp){ int temp = next[i-a]; if(i+temp < k) next[i] = temp; else{ checkmax(k, i); l = k-i; while(k < lenp && P[k] == P[l]){ ++k; ++l; } next[i] = l; a = i; } ++i; } next[lenp] = 0; } TY T[N]; int lent; int extend[N]; void getextend(){ int i, a, p, j(-1); for(i = 0; i < lent; ++i, --j){ if(j < 0 || i+next[i-a] >= p){ if(j < 0) j = 0, p = i; while(p < lent && j < lenp && T[p] == P[j]) ++p, ++j; extend[i] = j, a = i; } else extend[i] = next[i-a]; } } }; */ template<typename TY, int N> struct EXKMP { TY P[N]; int lenp; int next[N]; //next[i]表示str[i...len-1] 与 str[0...len-1]的最长公共前缀 void getnext() { next[0] = lenp; int k = 1, l = 0, a = 1; //含义: 当前位置, 匹配长度 while(k < lenp && P[k] == P[l]) { ++k; ++l; } next[1] = l; int i = 2; while(i < lenp) { int temp = next[i-a]; if(i+temp < k) next[i] = temp; else { checkmax(k, i); l = k-i; while(k < lenp && P[k] == P[l]) { ++k; ++l; } next[i] = l; a = i; } ++i; } next[lenp] = 0; } TY T[N]; int lent; int extend[N]; void getextend() { int i, a, p, j(-1); for(i = 0; i < lent; ++i, --j) { if(j < 0 || i+next[i-a] >= p) { if(j < 0) j = 0, p = i; while(p < lent && j < lenp && T[p] == P[j]) ++p, ++j; extend[i] = j, a = i; } else extend[i] = next[i-a]; } } }; void rev(char *sp, int len){ int l = 0, r = len-1; while(l < r){ swap(sp[l], sp[r]); ++l; --r; } } EXKMP<char, MAXN> exk; int cnt1[MAXN], cnt2[MAXN]; int main(){ int TC; scanf("%d", &TC); while(TC--){ scanf("%s%s", exk.T, exk.P); exk.lenp = strlen(exk.P); exk.lent = strlen(exk.T); exk.getnext(); exk.getextend(); memset(cnt1, 0, sizeof(cnt1[0])*(exk.lenp+1)); for(int i = 0; i < exk.lent; ++i) ++cnt1[exk.extend[i]]; for(int i = exk.lenp-1; i > 0; --i) cnt1[i] += cnt1[i+1]; rev(exk.P, exk.lenp); rev(exk.T, exk.lent); exk.getnext(); exk.getextend(); memset(cnt2, 0, sizeof(cnt2[0])*(exk.lenp+1)); for(int i = 0; i < exk.lent; ++i) ++cnt2[exk.extend[i]]; for(int i = exk.lenp-1; i > 0; --i) cnt2[i] += cnt2[i+1]; LL ans = 0; for(int i = 1; i < exk.lenp; ++i) ans += (LL)cnt1[i]*cnt2[exk.lenp-i]; printf("%lld\n", ans); } return 0; }