题意:求一个字符串的所有后缀在母串中的出现次数*后缀的长度的总和。
题目链接:http://acm.split.hdu.edu.cn/viewcode.php?rid=22147273
思路:先预处理sum[1...n]的值及sum[i]=1+..+i,然后将两个字符串反转,然后用扩展KMP求出翻转后的母串的EX数组。然后对任一个位置的他对答案的贡献就是sum[EX[i]];
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 1000005 typedef long long ll; const int MOD=1e9+7; ll num[maxn]; char s[maxn]; char t[maxn]; int Next[maxn]; int ex[maxn]; void init() { num[0]=0; for(int i=1;i<=maxn;i++) num[i]=(num[i-1]+i)%MOD; } void GETNEXT(char *str) { int i=0,j,po,len=strlen(str); Next[0]=len; while(str[i]==str[i+1]&&i+1<len) i++; Next[1]=i; po=1; for(i=2;i<len;i++) { if(Next[i-po]+i<Next[po]+po) Next[i]=Next[i-po]; else { j=Next[po]+po-i; if(j<0)j=0; while(i+j<len&&str[j]==str[j+i]) j++; Next[i]=j; po=i; } } } ll EXKMP(char *s1,char *s2) { int i=0,j,po,len=strlen(s1),l2=strlen(s2); GETNEXT(s2); ll sum=0; while(s1[i]==s2[i]&&i<l2&&i<len) i++; ex[0]=i; po=0; sum=(sum+num[ex[0]])%MOD; for(i=1;i<len;i++) { if(Next[i-po]+i<ex[po]+po) ex[i]=Next[i-po]; else { j=ex[po]+po-i; if(j<0)j=0; while(i+j<len&&j<l2&&s1[j+i]==s2[j]) j++; ex[i]=j; po=i; } sum=(sum+num[ex[i]])%MOD; } return sum; } int main() { init(); int k; scanf("%d",&k); while(k--) { scanf("%s%s",s,t); strrev(s); strrev(t); printf("%lld\n",EXKMP(s,t)); } return 0; }

浙公网安备 33010602011771号