考研路茫茫——单词情结
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4843 Accepted Submission(s): 1527
Problem Description
背单词,始终是复习英语的重要环节。在荒废了3年大学生涯后,Lele也终于要开始背单词了。
一天,Lele在某本单词书上看到了一个根据词根来背单词的方法。比如"ab",放在单词前一般表示"相反,变坏,离去"等。
于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢。更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义。
比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为
(2个) aa,ab,
(26个)aaa,aab,aac...aaz,
(26个)aba,abb,abc...abz,
(25个)baa,caa,daa...zaa,
(25个)bab,cab,dab...zab。
这个只是很小的情况。而对于其他复杂点的情况,Lele实在是数不出来了,现在就请你帮帮他。
Input
本题目包含多组数据,请处理到文件结束。
每组数据占两行。
第一行有两个正整数N和L。(0<N<6,0<L<2^31)
第二行有N个词根,每个词根仅由小写字母组成,长度不超过5。两个词根中间用一个空格分隔开。
Output
对于每组数据,请在一行里输出一共可能的单词数目。
由于结果可能非常巨大,你只需要输出单词总数模2^64的值。
Sample Input
2 3
aa ab
1 2
a
Sample Output
104
52
/* hdu 2243 考研路茫茫——单词情结(AC自动+矩阵) 给你m个子串,求包含至少一个子串的长度不大于n的字符串的种类数 所有可能: 26+26^2 + .... + 26^n 而且前面也求过一个子串都不包含的情况。即把他们的关系转换成矩阵mat 一个都不包含的情况: mat + mat^2 +..... + mat^n 对于求 次方和. mat+... mat^6 = mat+mat^2+mat^3 + mat^3*(mat+mat^2+mat^3) 于是求出两个的值然后减去即可 // 矩阵求a走m步到b的方案数 + A + A^2 + A^3 + ... + A^k的结果(两个矩阵的经典应用) hhh-2016-04-23 22:33:39 */ #include <iostream> #include <vector> #include <cstring> #include <string> #include <cstdio> #include <queue> #include <algorithm> #include <functional> #include <map> using namespace std; #define lson (i<<1) #define rson ((i<<1)|1) typedef unsigned long long ll; typedef unsigned int ul; const int maxn = 40010; int tot; struct Matrix { int len; ll ma[50][50]; Matrix() {} Matrix(int L) { len = L; } }; Matrix mult(Matrix ta,Matrix tb) { Matrix tc; tc.len = ta.len; for(int i = 0; i < ta.len; i++) { for(int j = 0; j < ta.len; j++) { tc.ma[i][j] = 0; for(int k = 0; k < ta.len; k++){ tc.ma[i][j] = tc.ma[i][j]+(ll)ta.ma[i][k]*tb.ma[k][j]; } } } return tc; } Matrix pow_mat(Matrix a,ll n) { Matrix cnt; cnt.len = a.len; memset(cnt.ma,0,sizeof(cnt.ma)); for(int i = 0 ; i < cnt.len; i++) cnt.ma[i][i] = 1; while(n) { if(n&1) cnt = mult(cnt,a); a = mult(a,a); n >>= 1; } return cnt; } Matrix Add(Matrix ta,Matrix tb) { Matrix tc; tc.len = ta.len; for(int i = 0;i < tc.len;i++) { for(int j = 0;j < tc.len;j++) { tc.ma[i][j] = (ta.ma[i][j]+tb.ma[i][j]); } } return tc; } struct Tire { int nex[50][26],fail[50],ed[50]; int root,L; int newnode() { for(int i = 0; i < 26; i++) nex[L][i] = -1; ed[L++] = 0; return L-1; } void ini() { L = 0,root = newnode(); } void inser(char buf[]) { int len = strlen(buf); int now = root; for(int i = 0; i < len; i++) { int ta = buf[i]-‘a‘; if(nex[now][ta] == -1) nex[now][ta] = newnode(); now = nex[now][ta]; } ed[now] ++; } void build() { queue<int >q; fail[root] = root; for(int i = 0; i < 26; i++) if(nex[root][i] == -1) nex[root][i] = root; else { fail[nex[root][i]] = root; q.push(nex[root][i]); } while(!q.empty()) { int now = q.front(); q.pop(); if(ed[fail[now]]) ed[now] = 1; for(int i = 0; i < 26; i++) { if(nex[now][i] == -1) nex[now][i] = nex[fail[now]][i]; else { fail[nex[now][i]] = nex[fail[now]][i]; q.push(nex[now][i]); } } } } Matrix to_mat() { Matrix mat(L); memset(mat.ma,0,sizeof(mat.ma)); for(int i = 0;i < L;i++) { for(int j = 0;j < 26;j++) { if(!ed[nex[i][j]]) mat.ma[i][nex[i][j]] ++; } } return mat; } }; Matrix mat; Matrix cal(int n) { if(n == 1) return mat; Matrix tp = cal(n/2); if(n & 1) { Matrix t = pow_mat(mat,n/2+1); tp = Add(tp,mult(t,tp)); tp = Add(tp,t); } else { Matrix t = pow_mat(mat,n/2); tp = Add(tp,mult(t,tp)); } return tp; } ll pow_mod(ll a,int n) { ll cnt = 1; while(n) { if(n&1) cnt = cnt*a; a = a*a; n >>= 1; } return cnt; } ll ca(int n) { if(n == 1) return 26; ll tp = ca(n/2); if(n & 1) { ll t = pow_mod(26,n/2+1); tp = tp+t+tp*t; } else { ll t = pow_mod(26,n/2); tp = tp+t*tp; } return tp; } Tire ac; char buf[20]; int main() { int n,m; while(scanf("%d%d",&m,&n) != EOF) { ac.ini(); for(int i = 1; i <= m; i++) { scanf("%s",buf); ac.inser(buf); } ac.build(); mat = ac.to_mat(); Matrix ans = cal(n); ll tans = ca(n); ll t = 0; for(int i = 0;i < ans.len;i++) { t += ans.ma[0][i]; } printf("%I64u\n",tans-t); } return 0; }