题目大意:
就是现在给出一些单词的词根,问长度不超过L ( 1 <= L < 2^31) 的只含小写英文字母的串中至少包含一个词根的串有多少个,输出结果对2^64取模输出
大致思路:
这道题和POJ 2778很像(题解戳这里),但是这题需要求得是含有词根的串的数量,很容易想到先求出不包含的个数,然后用全部的减去它即可,这个地方由于是长度不超过L,那么相对于POJ 2778来说需要求矩阵 A的 1~L次方的第一行的和,这里我用的是二分递归来求得等比矩阵和,但是容易RuntimeError(Stack_Overflow)后来减小了矩阵类的数组就过了
这里应该有更优的解法, 不过我还是就用了递归求矩阵的和过了
另外算26 + 26^2 + ... +26^L的时候也是构造的矩阵算的..
对于2^64取模可以利用unsigned long long 的溢出来解决,也就没什么好说的
代码如下:
Result : Accepted Memory : 1696 KB Time : 421 ms
/* * Author: Gatevin * Created Time: 2014/11/19 17:42:08 * File Name: Kagome.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; int n, L, bound; struct Matrix { unsigned long long a[26][26]; Matrix() { for(int i = 0; i < 26; i++) for(int j = 0; j < 26; j++) a[i][j] = i == j ? 1 : 0; return; } unsigned long long* operator[](int i) { return a[i]; } }; Matrix operator * (Matrix m1, Matrix m2) { Matrix rm; for(int i = 0; i < bound; i++) for(int j = 0; j < bound; j++) { rm[i][j] = 0; for(int k = 0; k < bound; k++) { rm[i][j] += m1[i][k]*m2[k][j]; } } return rm; } Matrix operator + (Matrix m1, Matrix m2) { Matrix rm; for(int i = 0; i < bound; i++) for(int j = 0; j < bound; j++) rm[i][j] = m1[i][j] + m2[i][j]; return rm; } Matrix quick(Matrix base, int pow)//快速幂 { Matrix I; while(pow) { if(pow & 1) I = I * base; base = base * base; pow >>= 1; } return I; } /* * 这个地方像我这么做容易爆栈,刚开始交的时候爆栈了好几次 * 应该有更好的方法来代替 */ Matrix Geo(Matrix base, int pow)//矩阵二分求和base + base^2 + base^3 + ... + base^pow { if(pow == 1) return base; Matrix I; if(pow & 1) return Geo(base, (pow - 1) >> 1) * ( I + quick(base, (pow - 1) >> 1)) + quick(base, pow); return Geo(base, pow >> 1)*( I + quick(base, pow >> 1)); } struct Trie { int next[6*6][26], fail[6*6]; bool end[6*6], vis[6*6]; int L, root; int newnode() { for(int i = 0; i < 26; i++) next[L][i] = -1; end[L++] = 0; return L - 1; } void init() { L = 0; root = newnode(); return; } void insert(char *s) { int now = root; for(; *s; s++) { if(next[now][*s - 'a'] == -1) next[now][*s - 'a'] = newnode(); now = next[now][*s - 'a']; } end[now] = 1; return; } void build()//建立状态转移图 { fail[root] = root; queue <int> Q; Q.push(root); while(!Q.empty()) { int now = Q.front(); Q.pop(); if(end[fail[now]]) end[now] = 1; for(int i = 0; i < 26; i++) if(next[now][i] == -1) next[now][i] = now == root ? root : next[fail[now]][i]; else { fail[next[now][i]] = now == root ? root : next[fail[now]][i]; Q.push(next[now][i]); } } return; } Matrix matrix()//BFS计算矩阵 { unsigned long long m[26][26]; memset(m, 0, sizeof(m)); memset(vis, 0, sizeof(vis)); queue <int> Q; Q.push(root); vis[root] = 1; while(!Q.empty()) { int now = Q.front(); Q.pop(); for(int i = 0; i < 26; i++) if(!end[next[now][i]]) { m[now][next[now][i]]++; if(!vis[next[now][i]]) { Q.push(next[now][i]); vis[next[now][i]] = 1; } } } Matrix R; vector <int> v; for(int i = 0; i < L; i++) if(vis[i]) v.push_back(i); for(unsigned int i = 0; i < v.size(); i++) for(unsigned int j = 0; j < v.size(); j++) R[i][j] = m[v[i]][v[j]]; bound = v.size(); return R; } }; Trie AC; int main() { char ts[8]; while(~scanf("%d %d", &n, &L)) { AC.init(); while(n--) { scanf("%s", ts); AC.insert(ts); } AC.build(); Matrix A = AC.matrix(); Matrix F = Geo(A, L); unsigned long long ans1 = 0; for(int i = 0; i < bound; i++) ans1 += F[0][i]; Matrix N; N[0][0] = 1; N[0][1] = 1; N[1][0] = 0; N[1][1] = 26; bound = 2; Matrix ALL = quick(N, L);//矩阵快速幂求等比数列26 + 26^2 + ... + 26^n的值 unsigned long long ans2 = ALL[0][1] + ALL[1][1] - 1; unsigned long long ans = ans2 - ans1; printf("%I64u\n", ans); } return 0; }