1 4 abab
6
题意:
求给定字符串含前缀的数量 (1 <= n <= 200000)
Abab,前缀为a,ab,aba,abab
abab中共有六个子串是前缀a a ab ab aba abab
所以答案为6
方法一:
Kmp+dp
Dp[i]=dp[Next[i]]+1,dp[i]表示以i为结尾包含的字符串的数量。
#include<bits/stdc++.h> using namespace std; const int maxn=1100000; int n,m; const int MOD=10007; char pattern[maxn]; int Next[maxn],ans,dp[maxn]; bool solve(int x1,int y1,int x2,int y2){ for(int i=x1,j=x2;i<=y1,j<=y2;i++,j++) if(pattern[i]!=pattern[j]) return false; return true; } void get_next(){ int i=0,j=-1; Next[0]=-1,dp[0]=0; while(i<m){ if(j==-1||pattern[j]==pattern[i]){ j++,i++; Next[i]=j; dp[i]=dp[Next[i]]+1; ans+=dp[i]; } else j=Next[j]; } } int main(){ int _; scanf("%d",&_); while(_--){ scanf("%d",&m); scanf("%s",pattern); ans=0; get_next(); printf("%d\n",ans%MOD); } return 0; }
方法二:
EKMP
Next[i]表示以i为开头的字符串与与0为开头的字符串的最大公共前缀。
#include<bits/stdc++.h> using namespace std; const int maxn=210000; char x[maxn]; int Next[maxn]; void pre_EKMP(int m){ Next[0]=m; int j=0; while(j+1<m&&x[j]==x[j+1]) j++; Next[1]=j; int k=1; for(int i=2;i<m;i++){ int p=Next[k]+k-1; int L=Next[i-k]; if(i+L<p+1) Next[i]=L; else{ j=max(0,p-i+1); while(i+j<m&&x[i+j]==x[j]) j++; Next[i]=j; k=i; } } } int main(){ int _,n; scanf("%d",&_); while(_--){ scanf("%d",&n); scanf("%s",x); pre_EKMP(n); int ans=0; for(int i=0;i<n;i++) ans+=Next[i]; printf("%d\n",ans%10007); } return 0; }