题意:
给一个字符串及其长度,问你该字符串的每个前缀在该字符串***有多少个
题解:
kmp的next数组含义:next[i]表示在1~i中前缀和后缀的最大长度。
举例:ababab
s : ababab
next : 001234
a: 2 + 1
ab: 2 + 1
aba: 1 + 1
abab: 1 + 1
ababa: 0 + 1
ababab: 0 + 1
其中每个+1表示他们前缀自身,
而2 2 1 1 0 0即除了自身以外在s中出现的次数。
(这里解释下因为是自身,因此不可能有前后缀相等的情况,故单独考虑)
那么有
i:1 2 3 4 5 6
next:0 0 1 2 3 4
i = 1,可以不考虑
i = 2,next = 0,故无前后缀相等情况
i = 3,next = 1,此时得到的是一个a(s[3]),next[1] = 0,结束
i = 4,next = 2,此时得到的是一个ab(s[3~4]),next[2] = 0,结束
i = 5,next = 3,此时得到的是一个aba(s[3~5]),next[3] = 1,此时得到的是一个a(s[5])
i = 6,next = 4,此时得到的是一个abab(s[3~6]),next[4] = 2,此时得到的是一个ab(s[5~6]),next[2] = 0,结束
括号中表明了当前的子串是对应哪部分中的子串。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 2e5 + 100, mod = 10007;
char s[N];
int ne[N];
int n;
void init_next(){
ne[1] = 0;
for(int i = 2, j = 0; i <= n; i++){
while(j && s[i] != s[j + 1]) j = ne[j];
if(s[i] == s[j + 1]) j++;
ne[i] = j;
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
scanf("%s", s + 1);
init_next();
int ans = n;
for(int i = 1; i <= n; i++){
int t = ne[i];
while(t){
ans = (ans + 1) % mod;
t = ne[t];
}
}
printf("%d\n", ans);
}
return 0;
}