您的位置:首页 > 其它

【NOI2014】动物园

2017-02-10 08:57 253 查看
题目链接:http://uoj.ac/problem/5

求:$${\prod _{i=1}^{L}num[i]\%(1e9+7)}$$,${num\left [ i \right ]}$表示:由字符串$S$的前$i$个字符构成的子串中,既是它的前缀,又是它的后缀,并且互不重合的字符串的个数。

利用KMP算法求出$next$数组,同时求出$cnt$数组,$cnt$数组定义为:由字符串$S$的前$i$个字符构成的子串中,既是它的前缀,又是它的后缀,可以的字符串的个数。

${cnt[i]=cnt[next[i]]+1}$

然后对于每一个位置,我们再做一遍形如找$next$数组的过程,但是这个时候指针一定要沿着$next$数组跳回到${\left \lfloor \frac{i}{2} \right \rfloor}$之前,我们知道对应点的$cnt$,那么这就满足了互不重合的条件,直接算贡献即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
#define maxn 1001000
#define llg long long
#define md 1000000007
#define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
llg n,m,next[maxn],T;
char s[maxn];
llg cnt[maxn];//既是1~i的后缀又是它的前缀的字符串个数

void find_next()
{
llg k=0;
next[1]=0; cnt[1]=1;
for (llg i=2;i<=n;i++)
{
while (k && s[k+1]!=s[i]) k=next[k];
if (s[k+1]==s[i]) k++;
next[i]=k;
cnt[i]=cnt[k]+1;
}
}

llg work()
{
llg k=0,ans=1;
for (llg i=2;i<=n;i++)
{
while (k && s[k+1]!=s[i]) k=next[k];
if (s[k+1]==s[i]) k++;
while (k*2>i) k=next[k];
ans=ans*(cnt[k]+1);
ans%=md;
}
return ans;
}

int main()
{
yyj("a");
cin>>T;
while (T--)
{
scanf("%s",s+1);
n=strlen(s+1);
find_next();
printf("%lld\n",work());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: