题目链接:http://icpc.njust.edu.cn/Problem/Hdu/3336/
题意就是要求一个字符串的所有前缀在字符串中出现的次数之和,我们容易想到kmp中的next数组,next[i]=j,表示存在一个长度为j的前缀与长度为j的后缀相同,本题的结果就是要对每一位的next数组都向前回退,回退的次数就是长度不同的前缀出现的次数。还可以采用dp的策略。
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef unsigned int ui; 4 typedef long long ll; 5 typedef unsigned long long ull; 6 #define pf printf 7 #define mem(a,b) memset(a,b,sizeof(a)) 8 #define prime1 1e9+7 9 #define prime2 1e9+9 10 #define pi 3.14159265 11 #define lson l,mid,rt<<1 12 #define rson mid+1,r,rt<<1|1 13 #define scand(x) scanf("%llf",&x) 14 #define f(i,a,b) for(int i=a;i<=b;i++) 15 #define scan(a) scanf("%d",&a) 16 #define dbg(args) cout<<#args<<":"<<args<<endl; 17 #define inf 0x3f3f3f3f 18 #define maxn 1000010 19 int n,m,t; 20 int nxt[maxn]; 21 char s[maxn]; 22 void getnxt() 23 { 24 int i=-1,j=0; 25 nxt[0]=-1; 26 while(j<n) 27 { 28 if(i==-1||s[i]==s[j]) 29 { 30 i++,j++; 31 nxt[j]=i;//不能用kmp优化的nxt,那样会损失数量 32 } 33 else i=nxt[i]; 34 } 35 } 36 int main() 37 { 38 //freopen("input.txt","r",stdin); 39 //freopen("output.txt","w",stdout); 40 std::ios::sync_with_stdio(false); 41 scan(t); 42 while(t--) 43 { 44 scan(n); 45 scanf("%s",s); 46 getnxt(); 47 int ans=0; 48 f(i,1,n)//查看以i-1为截至位置的公共前缀后缀 49 { 50 int j=i; 51 while(j>0) 52 { 53 ans++;//初始时本身还要算一次 54 if(ans>10007)ans-=10007; 55 j=nxt[j]; 56 } 57 } 58 pf("%d ",ans); 59 } 60 }
dp:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <time.h> 5 #include <cstdlib> 6 #include <cmath> 7 #include <algorithm> 8 using namespace std; 9 int const MOD = 10007; 10 int const MAXN = 200010; 11 char s[MAXN]; 12 int next[MAXN],dp[MAXN]; 13 inline void Get_Next(int n){ 14 memset(next,0,sizeof(next)); 15 for(int i = 1;i < n;i++){ 16 int j = next[i]; 17 while(j && s[i] != s[j]) j = next[j]; 18 if(s[i] == s[j]) next[i + 1] = j + 1; 19 else next[i + 1] = 0; 20 } 21 } 22 int main(){ 23 int T; 24 while(~scanf("%d",&T)){ 25 while(T--){ 26 int n; 27 scanf("%d",&n); 28 scanf("%s",s); 29 Get_Next(n); 30 for(int i = 0;i < n;i++){ 31 dp[i] = 1; 32 } 33 dp[0] = 0; 34 int sum = 0; 35 for(int i = 1;i <= n;i++){ 36 dp[i] = dp[next[i]] + 1; 37 sum = (sum + dp[i]) % MOD; 38 } 39 printf("%d ",sum); 40 } 41 } 42 return 0; 43 }