[hdu2243]考研路茫茫——单词情结(AC自动机+矩阵快速幂)
题意:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个。
解题关键:利用补集转化的思想,先求一个词根也不包含的单词个数,然后用总的减去即可。长度不超过L需要用矩阵维数增加一倍来处理前缀和。
这里还有第二种考虑思路,只增加一维,自己写一个三维矩阵验证一下即可,最后一列每一行代表每一行的前缀和。
方法1:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<queue> 8 using namespace std; 9 typedef unsigned long long ll; 10 const int N=26; 11 const int MAXN=42; 12 struct mat{ 13 ll m[101][101]; 14 }; 15 ll m,n; 16 struct Trie{ 17 int Next[MAXN][N],Fail[MAXN],root,tot; 18 bool End[MAXN]; 19 int newnode(){ 20 for(int i=0;i<N;i++) Next[tot][i]=-1; 21 End[tot++]=false; 22 return tot-1; 23 } 24 void init(){ 25 tot=0; 26 root=newnode(); 27 } 28 void insert(char buf[]){ 29 int len=strlen(buf),now=root,k; 30 for(int i=0;i<len;i++){ 31 k=buf[i]-'a'; 32 if(Next[now][k]==-1) Next[now][k]=newnode(); 33 now=Next[now][k]; 34 } 35 End[now]=true; 36 } 37 void build(){ 38 queue<int>que; 39 Fail[root]=root; 40 for(int i=0;i<N;i++){ 41 if(Next[root][i]==-1) Next[root][i]=root; 42 else{ 43 Fail[Next[root][i]]=root; 44 que.push(Next[root][i]); 45 } 46 } 47 while(!que.empty()){ 48 int now=que.front(); 49 que.pop(); 50 if(End[Fail[now]]) End[now]=true; 51 for(int i=0;i<N;i++){ 52 if(Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i]; 53 else{ 54 Fail[Next[now][i]]=Next[Fail[now]][i]; 55 que.push(Next[now][i]); 56 } 57 } 58 } 59 } 60 mat get_mat(){ 61 mat B={0}; 62 for(int i=0;i<tot;i++){ 63 if(End[i]) continue; 64 for(int j=0;j<N;j++){ 65 if(End[Next[i][j]]==false) B.m[i][Next[i][j]]++;//不能直接置1 66 } 67 } 68 for(int i=0;i<tot;i++){ 69 B.m[i+tot][i]=B.m[i+tot][i+tot]=1; 70 } 71 return B; 72 } 73 }; 74 75 mat mul(mat &A,mat &B,int len){ 76 mat C={0}; 77 for(int i=0;i<len;i++){ 78 for(int j=0;j<len;j++){ 79 for(int k=0;k<len;k++){ 80 C.m[i][j]+=A.m[i][k]*B.m[k][j]; 81 } 82 } 83 } 84 return C; 85 } 86 87 mat pow(mat A,ll n,int len){ 88 mat B={0}; 89 for(int i=0;i<len;i++) B.m[i][i]=1; 90 while(n){ 91 if(n&1) B=mul(B,A,len); 92 A=mul(A,A,len); 93 n>>=1; 94 } 95 return B; 96 } 97 98 Trie ac; 99 char buf[10]; 100 int main(){ 101 while(scanf("%llu%llu",&m,&n)!=EOF){ 102 ac.init(); 103 for(int i=0;i<m;i++){ 104 scanf("%s",buf); 105 ac.insert(buf); 106 } 107 ac.build(); 108 mat B=ac.get_mat(); 109 B=pow(B,n+1,2*ac.tot); 110 mat C={0},D={0},E={0}; 111 for(int i=0;i<ac.tot;i++) C.m[i][i]=1; 112 D=mul(B,C,2*ac.tot); 113 E.m[0][0]=26,E.m[0][1]=0,E.m[1][0]=E.m[1][1]=1; 114 E=pow(E,n+1,2); 115 ll res1=0,res2=E.m[1][0]; 116 for(int i=0;i<ac.tot;i++){ 117 if(i==0) D.m[ac.tot][i]-=1; 118 res1+=D.m[ac.tot][i]; 119 } 120 printf("%llu\n",res2-1-res1); 121 } 122 return 0; 123 }
法2:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<queue> 8 using namespace std; 9 typedef unsigned long long ll; 10 const int N=26; 11 const int MAXN=42; 12 struct mat{ 13 ll m[101][101]; 14 }; 15 ll m,n; 16 struct Trie{ 17 int Next[MAXN][N],Fail[MAXN],root,tot; 18 bool End[MAXN]; 19 int newnode(){ 20 for(int i=0;i<N;i++) Next[tot][i]=-1; 21 End[tot++]=false; 22 return tot-1; 23 } 24 void init(){ 25 tot=0; 26 root=newnode(); 27 } 28 void insert(char buf[]){ 29 int len=strlen(buf),now=root,k; 30 for(int i=0;i<len;i++){ 31 k=buf[i]-'a'; 32 if(Next[now][k]==-1) Next[now][k]=newnode(); 33 now=Next[now][k]; 34 } 35 End[now]=true; 36 } 37 void build(){ 38 queue<int>que; 39 Fail[root]=root; 40 for(int i=0;i<N;i++){ 41 if(Next[root][i]==-1) Next[root][i]=root; 42 else{ 43 Fail[Next[root][i]]=root; 44 que.push(Next[root][i]); 45 } 46 } 47 while(!que.empty()){ 48 int now=que.front(); 49 que.pop(); 50 if(End[Fail[now]]) End[now]=true; 51 for(int i=0;i<N;i++){ 52 if(Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i]; 53 else{ 54 Fail[Next[now][i]]=Next[Fail[now]][i]; 55 que.push(Next[now][i]); 56 } 57 } 58 } 59 } 60 mat get_mat(){ 61 mat B={0}; 62 for(int i=0;i<=tot;i++) B.m[i][tot]=1; 63 for(int i=0;i<tot;i++){ 64 if(End[i]) continue; 65 for(int j=0;j<N;j++){ 66 if(End[Next[i][j]]==false) B.m[i][Next[i][j]]++;//不能直接置1 67 } 68 } 69 return B; 70 } 71 }; 72 73 mat mul(mat &A,mat &B,int len){ 74 mat C={0}; 75 for(int i=0;i<len+1;i++){ 76 for(int j=0;j<len+1;j++){ 77 for(int k=0;k<len+1;k++){ 78 C.m[i][j]+=A.m[i][k]*B.m[k][j]; 79 } 80 } 81 } 82 return C; 83 } 84 85 mat pow(mat A,ll n,int len){ 86 mat B={0}; 87 for(int i=0;i<len;i++) B.m[i][i]=1; 88 while(n){ 89 if(n&1) B=mul(B,A,len); 90 A=mul(A,A,len); 91 n>>=1; 92 } 93 return B; 94 } 95 96 Trie ac; 97 char buf[10]; 98 int main(){ 99 while(scanf("%llu%llu",&m,&n)!=EOF){ 100 ac.init(); 101 for(int i=0;i<m;i++){ 102 scanf("%s",buf); 103 ac.insert(buf); 104 } 105 ac.build(); 106 mat B=ac.get_mat(); 107 108 ll res1,res2; 109 B=pow(B,n+1,ac.tot); 110 res1=B.m[0][ac.tot]-1; 111 112 mat E={0}; 113 E.m[0][0]=26,E.m[0][1]=0,E.m[1][0]=E.m[1][1]=1; 114 E=pow(E,n+1,2); 115 res2=E.m[1][0]; 116 117 printf("%llu\n",res2-1-res1); 118 } 119 return 0; 120 }