4175: 小G的电话本
Time Limit: 45 Sec Memory Limit: 256 MB
Submit: 262 Solved: 60
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;
}