题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3336
6
a b a b a b ‘\0’
下标i: 0 1 2 3 4 5 6
Next: -1 0 0 1 2 3 4
dp: 0 1 1 2 2 3 3
dp[ 1 ]=1表示目前:‘a’出现一次
dp[ 2 ]=1:同上:“ab”
dp[ 3 ]=2表示“abab”一次,“ab”一次
。
。
。
dp[ 6 ]=3表示首字母‘a’在整个的出现次数
/*题解:http://www.cnblogs.com/wuyiqi/archive/2012/01/05/2313746.html 利用kmp中的匹配原理可以完美的解决此题 a---------d----- -----a---------d i j 如上所示,假设两串字符完全相等,next[j]=i,代表s[1...i]==sum[j-i+1....j],这一段其实就是前缀 i~j之间已经不可能有以j结尾的子串是前缀了,不然next【j】就不是 i 了 设dp【i】:以string[i]结尾的子串总共含前缀的数量 所以dp[i]=dp[next[i]]+1,即以i结尾的子串中含前缀的数量加上前j个字符这一前缀*/ #include <stdio.h> #include <string.h> #define MAXN 200002 #define MOD 10007 char text[MAXN]; int next[MAXN],dp[MAXN]; void getNext() { int i=0,j=-1; next[0]=-1; while(text[i]!='\0') { if(j==-1||text[i]==text[j]) { i++; j++; next[i]=j; } else j=next[j]; } } int main() { int test,n,i,sum; scanf("%d",&test); while(test--) { scanf("%d",&n); scanf("%s",text); getNext(); sum=0; memset(dp,0,sizeof(dp)); for(i=1;i<=n;++i) { dp[i]=(dp[next[i]]+1)%MOD; sum=(sum+dp[i])%MOD; } printf("%d\n",sum); } return 0; }
#include <stdio.h> #include <string.h> #define MAXN 200002 #define MOD 10007 char text[MAXN]; int next[MAXN],count[MAXN]; void getNext() { int i=0,j=-1; next[0]=-1; while(text[i]!='\0') { if(j==-1||text[i]==text[j]) { count[i]++;//以text[0...i]为前缀的字符串第一次出现 i++; j++; next[i]=j; if(j>0)//以text[0...j-1]为前缀的字符串出现两次及以上 count[j-1]++; } else j=next[j]; } } int main() { int test,n,i,sum; scanf("%d",&test); while(test--) { memset(count,0,sizeof(count)); scanf("%d",&n); scanf("%s",text); getNext(); sum=0; for(i=0;i<n;++i) { sum=(sum+count[i])%MOD; } printf("%d\n",sum); } return 0; }