题意:
参考了大佬的博客:https://blog.csdn.net/guodongxiaren/article/details/25742103
求字符串的每一个前缀在字符串出现次数的总和(可重叠)
思路:
以字符串ababa,求它的sum(前缀出现次数和)。我们可以得到它的next数组:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
模式串 | a | b | a | b | a | |
nxt 数组 | -1 | 0 | 0 | 1 | 2 | 3 |
代入到代码中,和abab相比,只多了一位。所以直接看 i 等于n(n为5)的时候,在sum=6(abab的sum值为6)的基础上来看。
- j=i=5 //表示的是ababa这个长度为5的最长前缀
- while(j)成立,sum=6+1=7
- j=next[5]=3 //表示的是aba这个长度为3的前缀
- while(j)成立,sum=7+1=8
- j=next[3]=1 //表示的是a这个长度为1的最短前缀
- while(j)成立,sum=8+1=9
- j=next[1]=0.
- while(j)不成立,结束。
- 最终sum=9
字符串所有前缀在字符串中出现次数的和 = 所有位置 nxt 的值一直往前递归到0的次数和 + 字符串的长度(长度为几就有几个不同的前缀)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mod 10007
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
char s[maxn];
int nxt[maxn];
int n;
void getnxt()
{
int i,j;
i = 0;
j = nxt[0] = -1;
while(i<n)
{
if(j==-1 || s[i]==s[j])
{
i++,j++;
nxt[i] = j;
}
else
j = nxt[j];
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(nxt,0,sizeof(nxt));
scanf("%d",&n);
scanf("%s",s);
getnxt();
int ans = 0;
for(int i=1;i<=n;i++)
{
int j = i;
while(j)
{
ans = (ans+1)%mod;
j = nxt[j];
}
}
printf("%d\n",ans);
}
return 0;
}