4175: 小G的电话本
Time Limit: 45 Sec Memory Limit: 256 MBSubmit: 226 Solved: 52
[ 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
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
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = (1 << 18) + 233;
typedef long long LL;
const LL g = 5;
const LL mo = 1005060097;
int n,m,k,N,cnt,Inv,last,rt,ch[maxn][26],len[maxn],du[maxn]
,fail[maxn],siz[maxn],w[maxn],_w[maxn],f[maxn],Ans[maxn];
char s[maxn]; bool vis[maxn];
queue <int> Q;
inline int Mul(const LL &x,const LL &y) {return x * y % mo;}
inline int Add(const int &x,const int &y) {return x + y < mo ? x + y : x + y - mo;}
inline int Dec(const int &x,const int &y) {return x - y >= 0 ? x - y : x - y + mo;}
int ksm(int x,int y)
{
int ret = 1;
for (; y; y >>= 1)
{
if (y & 1) ret = Mul(ret,x);
x = Mul(x,x);
}
return ret;
}
void Extend(int Len,int Nex)
{
int p = last,np = ++cnt;
last = np; len[np] = Len; siz[np] = 1;
while (p && !ch[p][Nex])
ch[p][Nex] = np,p = fail[p];
if (!p) {fail[np] = rt; return;}
int q = ch[p][Nex];
if (len[q] - len[p] == 1) fail[np] = q;
else
{
int nq = ++cnt; len[nq] = len[p] + 1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fail[nq] = fail[q]; fail[q] = fail[np] = nq;
while (p && ch[p][Nex] == q)
ch[p][Nex] = nq,p = fail[p];
}
}
void Pre_Work()
{
cin >> k >> m; rt = cnt = last = 1;
N = 1; while (N <= m) N <<= 1; N <<= 1;
w[0] = 1; w[1] = ksm(g,(mo - 1) / N);
for (int i = 2; i <= N; i++) w[i] = Mul(w[i - 1],w[1]);
for (int i = 0; i <= N; i++) _w[i] = w[N - i];
scanf("%s",s + 1); n = strlen(s + 1);
for (int i = 1; i <= n; i++) Extend(i,s[i] - 'a');
for (int i = 2; i <= cnt; i++) ++du[fail[i]];
for (int i = 2; i <= cnt; i++) if (!du[i]) Q.push(i);
while (!Q.empty())
{
int k = Q.front(); Q.pop(); siz[fail[k]] += siz[k];
--du[fail[k]]; if (!du[fail[k]]) Q.push(fail[k]);
}
for (int i = 2; i <= cnt; i++)
if (siz[i] <= m) f[siz[i]] = Add(f[siz[i]],1LL * (len[i] - len[fail[i]]) * siz[i] % mo);
Ans[0] = 1; Inv = ksm(N,mo - 2);
}
void Rader(int *F)
{
int j = (N >> 1);
for (int i = 1; i < N - 1; i++)
{
if (i < j) swap(F[i],F[j]); int k = (N >> 1);
while (j >= k) j -= k,k >>= 1; j += k;
}
}
void NTT(int *F,int *w,int on)
{
Rader(F);
for (int k = 2; k <= N; k <<= 1)
for (int i = 0; i < N; i += k)
{
int now = 0;
for (int j = i; j < i + (k >> 1); j++)
{
int u = F[j],v = Mul(w[now],F[j + (k >> 1)]);
F[j] = Add(u,v); F[j + (k >> 1)] = Dec(u,v); now += N / k;
}
}
if (on == -1) for (int i = 0; i < N; i++) F[i] = Mul(F[i],Inv);
}
void Mul_Ans()
{
NTT(Ans,w,1); NTT(f,w,1);
for (int i = 0; i < N; i++) Ans[i] = Mul(Ans[i],f[i]);
NTT(Ans,_w,-1); NTT(f,_w,-1);
for (int i = m + 1; i < N; i++) Ans[i] = 0;
}
void Mul_f()
{
NTT(f,w,1); for (int i = 0; i < N; i++) f[i] = Mul(f[i],f[i]);
NTT(f,_w,-1); for (int i = m + 1; i < N; i++) f[i] = 0;
}
void Ksm()
{
for (; k; k >>= 1)
{
if (k & 1) Mul_Ans();
Mul_f();
}
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
Pre_Work(); Ksm();
cout << Ans[m] << endl;
return 0;
}