/* 巧妙地使用fail数组 根据fail数组的定义 fail[i] 有 长度为i的子串最长公共前后缀为fail[i] 比如样例 fail 0 0 1 2 那么我们维护一个ans[i]表示到i位置的时候 前i位置子串的匹配次数 比如 a b a ans[1]=1 ans[2]=1 到ans[3]的时候 发现 a 又出现了一边 说明之前的a子串统计少了 相应的可以根据 fail找到a的位置在统计一遍就不漏了 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 200010 using namespace std; int T,an,ans[maxn],l,fail[maxn]; char s[maxn]; void kmp_init() { int p=0; for(int i=2;i<=l;i++) { while(p&&s[p+1]!=s[i]) p=fail[p]; if(s[p+1]==s[i]) p++; fail[i]=p; } } int main() { scanf("%d",&T); while(T--) { scanf("%d",&l); scanf("%s",s+1); an=0;//初始化害死人 memset(ans,0,sizeof(ans)); memset(fail,0,sizeof(fail)); kmp_init(); for(int i=1;i<=l;i++) { ans[i]=1; if(fail[i])//如果当前的子串存在公共前后缀 //说明这个公共缀之前统计少了 ans[i]+=ans[fail[i]]; an=(an+ans[i])%10007; } printf("%d\n",an); } }
时间: 2024-10-29 19:09:05