bzoj 4175 小G的电话本

来源:互联网 发布:用matlab求矩阵方程 编辑:程序博客网 时间:2024/05/22 09:24

4175: 小G的电话本

Time Limit: 45 Sec  Memory Limit: 256 MB
Submit: 262  Solved: 60
[Submit][Status][Discuss]

Description

 小G是一个商人,他有一个电话本。电话本上记下了许多联系人,如timesqr、orzyhb等等。不过Tony对其中的某个联系人的名字S特别感兴趣,他从中提取出了这个联系人的名字中的所有片段,如提取出orz的   o、r、z、or、rz、orz等等。现在他想请你统计有多少个长度为k的片段对(P[1], P[2], P[3], ..., P[k]),使得在该片段对中所有片段在S中出现次数之和为他的幸运数m?注意两个片段对不同当且仅当两个片段对的某一位的片段不同,两个片段不同当且仅当这两个片段在S中的位置不同

Input

第一行两个整数k和m,意义见题目描述;第二行给出一个字符串表示Tony喜欢的联系人名字S。

Output

输出一行一个整数ans,表示答案模1005060097。

Sample Input

3 4
aaaaa

Sample Output

6

HINT

【样例解释】



符合要求的片段对一共有6种(用[p]s表示起始位置为p的s片段):


([1]aaaa, [1]aaaaa, [1]aaaaa)、([1]aaaaa, [1]aaaa, [1]aaaaa)、


([1]aaaaa, [1]aaaaa, [1]aaaa)、([2]aaaa, [1]aaaaa, [1]aaaaa)、


([1]aaaaa, [2]aaaa, [1]aaaaa)、([1]aaaaa, [1]aaaaa, [2]aaaa)。


【数据范围】


设n表示联系人的名字的长度,联系人的名字只包含小写字母。


对于10%的数据,1 <= n <= 100, k = 1。


对于40%的数据,1 <= n <= 100, k = 2。


对于70%的数据,1 <= n <= 100000, 1 <= k <= 10。


对于100%的数据,1 <= n <= 100000, 1 <= k <= 100000, 1 <= m <= n。

Source





【分析】

bzoj竟然连long long都能卡5s,真是6的飞起

我的青春就浪费在愚蠢的long long上了...QaQ


这题思路很好想...先求出来每个子串的出现次数,用后缀自动机解决...

如果一个子串出现k次,那么num[k]++。

这相当于构造了一个多项式...问题转换为了求多项式的n次方中x^m的系数


多项式快速幂+NTT



【代码】


//bzoj 4175 小G的电话本 #include<bits/stdc++.h>#define ll long long#define M(a) memset(a,0,sizeof a)#define fo(i,j,k) for(int i=j;i<=k;i++)using namespace std;const int mxn=200005;const int mod=1005060097;ll num[mxn];char s[mxn];int N,M,L,n,m,p,q,np,nq,tot,len;int step[mxn],pre[mxn],son[mxn][28];int B[mxn],C[mxn],rig[mxn],R[mxn<<1];int a[mxn<<1],b[mxn<<1],c[mxn<<1];inline int power(int x,int k){    int res=1;    while(k)    {        if(k&1) res=(ll)res*x%mod;        x=(ll)x*x%mod,k>>=1;    }    return res;}inline void NTT(int *a,int f){    fo(i,0,n-1) if(i<R[i]) swap(a[i],a[R[i]]);    for(int i=1;i<n;i<<=1)    {        int wn=power(5,(mod-1)/(i<<1));        for(int j=0;j<n;j+=(i<<1))        {            int w=1;            for(int k=0;k<i;k++,w=(ll)w*wn%mod)            {                int x=a[j+k],y=(ll)w*a[j+k+i]%mod;                a[j+k]=(x+y)%mod;                a[j+k+i]=(x-y+mod)%mod;            }        }    }    if(f==-1)    {        reverse(a+1,a+n);        int rev=power(n,mod-2);        fo(i,0,n-1) a[i]=(ll)a[i]*rev%mod;    }}inline void x_power(){    m=M+M;for(n=1;n<=m;n<<=1) L++;    fo(i,0,n-1) R[i]=(R[i>>1]>>1)|((i&1)<<L-1);    fo(i,0,M) a[i]=b[i]=num[i];    int k=N-1;    while(k)    {        if(k&1)        {            NTT(a,1),NTT(b,1);            fo(i,0,n) a[i]=(ll)a[i]*b[i]%mod;            NTT(a,-1);            fo(i,M+1,n) a[i]=0;        }//      printf("%d %d %d %d\n",b[1],b[2],b[3],b[4]);        if(!(k&1)) NTT(b,1);        fo(i,0,n) b[i]=(ll)b[i]*b[i]%mod;        NTT(b,-1);        fo(i,M+1,n) b[i]=0;//      printf("%d %d %d %d\n",b[1],b[2],b[3],b[4]);        k>>=1;    }    printf("%d\n",a[M]);}inline void sam(){    tot=np=1;    scanf("%s",s+1);    len=strlen(s+1);    fo(i,1,len)    {        int c=s[i]-'a'+1;p=np;        step[np=(++tot)]=step[p]+1;        rig[np]=1;        while(p && !son[p][c])          son[p][c]=np,p=pre[p];        if(!p) {pre[np]=1;continue;}        q=son[p][c];        if(step[q]==step[p]+1) pre[np]=q;        else        {            step[nq=(++tot)]=step[p]+1;            memcpy(son[nq],son[q],sizeof son[q]);            pre[nq]=pre[q];            pre[q]=pre[np]=nq;            while(p && son[p][c]==q)              son[p][c]=nq,p=pre[p];        }    }}inline void basesort(){    fo(i,1,tot) B[step[i]]++;    fo(i,1,tot) B[i]+=B[i-1];    fo(i,1,tot) C[B[step[i]]--]=i;    for(int i=tot;i>=1;i--)    {        int now=C[i],fa=pre[now];        rig[fa]+=rig[now];    }    fo(i,2,tot) (num[rig[i]]+=(ll)rig[i]*(step[i]-step[pre[i]]))%=mod;}int main(){    scanf("%d%d",&N,&M);    sam(),basesort(),x_power();    return 0;}