题目链接: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;
}