Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Others)
Total Submission(s): 2523 Accepted Submission(s): 934
题目链接:HDU 6153
扩展KMP解决的是对于每一个每一个$S$的后缀$Suffix(i)$,它与$T$串最长的公共前缀是多少,即它与$T$串各自从头开始能匹配几个,一旦有一个不匹配即结束。
这题求的是每一个$S_2$的后缀出现在$S_1$有几次,那么我们可以把两个串都反过来变成求$S_2$的前缀在$S_1$出现过几次,这样就可以发现如果$S_2$的前缀$prefix(j)$与$S_1$的后缀$Suffix(i)$的最长公共前缀为$k$,那么包括$prefix(j)$以及$j$以前的前缀均在$S_1$的$i$处出现过一次,贡献为$(k+1)*k/2$,那么这样求一遍$extend[]$数组后统计答案即可
代码:
#include <stdio.h> #include <iostream> #include <algorithm> #include <cstdlib> #include <cstring> #include <bitset> #include <string> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define fin(name) freopen(name,"r",stdin) #define fout(name) freopen(name,"w",stdout) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 1e6 + 7; const LL mod = 1000000007LL; char s[N], t[N]; int nxt[N], ex[N]; void getnxt(char T[], int len, int nxt[]) { nxt[0] = len; int a; int p; for (int i = 1, j = -1; i < len; i++, j--) { if (j < 0 || i + nxt[i - a] >= p) { if (j < 0) p = i, j = 0; while (p < len && T[p] == T[j]) p++, j++; nxt[i] = j; a = i; } else nxt[i] = nxt[i - a]; } } void getextend(char S[], char T[], int ls, int lt, int extend[], int nxt[]) { getnxt(T, lt, nxt); //得到next int a; int p; //记录匹配成功的字符的最远位置p,及起始位置a for (int i = 0, j = -1; i < ls; i++, j--) //j即等于p与i的距离,其作用是判断i是否大于p(如果j<0,则i大于p) { if (j < 0 || i + nxt[i - a] >= p) //i大于p(其实j最小只可以到-1,j<0的写法方便读者理解程序), { //或者可以继续比较(之所以使用大于等于而不用等于也是为了方便读者理解程序) if (j < 0) p = i, j = 0; //如果i大于p while (p < ls && j < lt && S[p] == T[j]) p++, j++; extend[i] = j; a = i; } else extend[i] = nxt[i - a]; } } int main(void) { int T, i; scanf("%d", &T); while (T--) { scanf("%s%s", s, t); int la = strlen(s); int lb = strlen(t); reverse(s, s + la); reverse(t, t + lb); getnxt(t, lb, nxt); getextend(s, t, la, lb, ex, nxt); LL ans = 0; for (i = 0; i < la; ++i) { LL temp = (LL)ex[i] * ((LL)ex[i] + 1LL) / 2LL; ans = (ans + temp) % mod; } printf("%I64d\n", ans); } return 0; }
原文:http://www.cnblogs.com/Blackops/p/7545696.html