4175: 小G的电话本

    xiaoxiao2021-03-25  123

    4175: 小G的电话本

    Time Limit: 45 Sec  Memory Limit: 256 MB Submit: 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

    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

    [ Submit][ Status][ Discuss] 对于原串,构造出它的sam,就可以统计出每种子串出现次数 设计数组f[i],为出现次数为i的串的种类数 那么f的m次方的第k位就是答案了,用NTT解决即可 #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; }

    转载请注明原文地址: https://ju.6miu.com/read-20276.html

    最新回复(0)