感谢http://blog.henix.info/blog/poj-2778-aho-corasick-dp.html给的灵感
看数据规模,很容易想到用矩阵求解,关键是如何得到原始矩阵。上面连接博客中的方法给力,在AC自动机上确定出每一个点的跳转点,即jump数组,表示该点可以跳转到的点。
利用每个点的jump数组,我们就可以确定出一张跳转表,也即时我们需要的原始矩阵。
对每个点,如果它不是病毒片段的结尾,那么它便是安全的。我们很容易可以理解,安全点到安全点之间的跳转,总是安全的。给每个安全点一个编号,构建一个矩阵a[][]。
那么a[i][j]就表示从第j个安全点能够跳转到第i个安全点的数量。将这个矩阵开k次方,取第一列中的所有项之和,就是答案了。
View Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 using namespace std; 5 #define mod 100000 6 7 struct node 8 { 9 struct node *fail; 10 struct node *next[4]; 11 struct node *jump[4]; 12 int cnt; 13 }; 14 15 node root[110]; 16 int num; 17 int n,m; 18 char str[11]; 19 20 int get_index(char c) 21 { 22 if(c=='A') 23 return 0; 24 if(c=='C') 25 return 1; 26 if(c=='T') 27 return 2; 28 return 3; 29 } 30 31 void insert(char word[]) 32 { 33 int i=0; 34 struct node *tmp=root; 35 while(word[i]) 36 { 37 int b=get_index(word[i]); 38 if(tmp->next[b]==NULL) 39 { 40 memset(root+num,0,sizeof(struct node)); 41 tmp->next[b]=root+num; 42 num++; 43 } 44 tmp=tmp->next[b]; 45 i++; 46 } 47 tmp->cnt++; 48 } 49 50 node *q[110]; 51 int head,tail; 52 53 void add_Fail() 54 { 55 head=tail=0; 56 q[tail++]=root; 57 while(head<tail) 58 { 59 node *x=q[head++]; 60 int i; 61 for(i=0;i<4;i++) 62 { 63 node *t=x->fail; 64 while(t!=NULL && t->next[i]==NULL) 65 t=t->fail; 66 if(x->next[i]!=NULL) 67 { 68 q[tail++]=x->next[i]; 69 if(t==NULL) 70 x->next[i]->fail=root; 71 else 72 { 73 x->next[i]->fail=t->next[i]; 74 if(t->next[i]->cnt>0) 75 x->next[i]->cnt=1; 76 } 77 x->jump[i]=x->next[i]; 78 } 79 else 80 { 81 if(t==NULL) 82 x->jump[i]=root; 83 else 84 x->jump[i]=t->next[i]; 85 } 86 } 87 } 88 } 89 90 struct MAT 91 { 92 int a[110][110]; 93 }; 94 95 int len; 96 97 MAT getE() 98 { 99 MAT ans; 100 int i,j; 101 for(i=0;i<len;i++) 102 for(j=0;j<len;j++) 103 ans.a[i][j]=0; 104 for(i=0;i<len;i++) 105 ans.a[i][i]=1; 106 return ans; 107 } 108 109 MAT mulPow(MAT a,MAT b) 110 { 111 MAT ans; 112 int i,j,k; 113 for(i=0;i<len;i++) 114 { 115 for(j=0;j<len;j++) 116 { 117 __int64 sum=0; 118 for(k=0;k<len;k++) 119 { 120 sum+=(__int64)a.a[i][k]*b.a[k][j]; 121 sum%=mod; 122 } 123 ans.a[i][j]=sum; 124 } 125 } 126 return ans; 127 } 128 129 MAT solve(MAT a,int k) 130 { 131 MAT ans; 132 ans=getE(); 133 while(k) 134 { 135 if(k&1) 136 { 137 ans=mulPow(ans,a); 138 } 139 a=mulPow(a,a); 140 k=k>>1; 141 } 142 return ans; 143 } 144 145 int main() 146 { 147 int i,j,k; 148 MAT res; 149 //freopen("D:\\in.txt","r",stdin); 150 while(scanf("%d%d",&n,&m)==2) 151 { 152 num=1; 153 memset(root,0,sizeof(struct node)); 154 for(i=0;i<n;i++) 155 { 156 scanf("%*c%s",str); 157 insert(str); 158 } 159 add_Fail(); 160 int id=0,id1; 161 for(i=0;i<num;i++) 162 { 163 if(root[i].cnt==0) 164 { 165 id1=0; 166 for(j=0;j<num;j++) 167 { 168 if(root[j].cnt==0) 169 { 170 int count=0; 171 for(k=0;k<4;k++) 172 { 173 if(root[j].jump[k]==root+i) 174 count++; 175 } 176 res.a[id][id1]=count; 177 id1++; 178 } 179 } 180 id++; 181 } 182 } 183 len=id; 184 res=solve(res,m); 185 int ans=0; 186 for(i=0;i<len;i++) 187 { 188 ans=(ans+res.a[i][0])%mod; 189 ans%=mod; 190 } 191 printf("%d\n",ans); 192 } 193 return 0; 194 }
spoj 1676 http://www.spoj.pl/problems/GEN/这个题和上面那个题大概意思是一样的。只不过这题数据规模大一些,上面的程序矩阵乘积的时候并没有对取模运算做任何判断,
对于矩阵连乘的问题,取模运算是消耗时间的大客户。这题只要对取模运算加上判断,尽量少用就可以过了,不然就是tle了。。。
View Code
1 #include<iostream> 2 #include<string> 3 #include<stdio.h> 4 #include<memory.h> 5 using namespace std; 6 #define mod 10007 7 8 struct node 9 { 10 struct node *fail; 11 struct node *next[26]; 12 struct node *jump[26]; 13 int cnt; 14 }; 15 16 node root[61]; 17 int num; 18 int n,m; 19 char str[7]; 20 21 void insert(char word[]) 22 { 23 int i=0; 24 node *tmp=root; 25 while(word[i]) 26 { 27 int b=word[i]-'A'; 28 if(tmp->next[b]==NULL) 29 { 30 tmp->next[b]=root+num; 31 memset(root+num,0,sizeof(struct node)); 32 num++; 33 } 34 tmp=tmp->next[b]; 35 i++; 36 } 37 tmp->cnt=1; 38 } 39 40 node *q[100]; 41 int head,tail; 42 43 void add_Fail() 44 { 45 head=tail=0; 46 q[tail++]=root; 47 while(head<tail) 48 { 49 node *x=q[head++]; 50 for(int i=0;i<26;i++) 51 { 52 node *t=x->fail; 53 while(t!=NULL && t->next[i]==NULL) 54 t=t->fail; 55 if(x->next[i]!=NULL) 56 { 57 q[tail++]=x->next[i]; 58 if(t==NULL) 59 x->next[i]->fail=root; 60 else 61 { 62 x->next[i]->fail=t->next[i]; 63 if(t->next[i]->cnt) 64 x->next[i]->cnt=1; 65 } 66 x->jump[i]=x->next[i]; 67 } 68 else 69 { 70 if(t!=NULL) 71 x->jump[i]=t->next[i]; 72 else 73 x->jump[i]=root; 74 } 75 } 76 } 77 } 78 79 struct Mat 80 { 81 int a[61][61]; 82 }; 83 Mat e; 84 int len,all; 85 86 Mat mulPow(Mat a,Mat b) 87 { 88 int i,j,k; 89 Mat ans; 90 for(i=0;i<len;i++) 91 { 92 for(j=0;j<len;j++) 93 { 94 ans.a[i][j]=0; 95 for(k=0;k<len;k++) 96 { 97 if(a.a[i][k] && b.a[k][j]) 98 { 99 ans.a[i][j]+=a.a[i][k]*b.a[k][j]; 100 if(ans.a[i][j]>=mod) 101 ans.a[i][j]%=mod; 102 } 103 } 104 } 105 } 106 return ans; 107 } 108 109 Mat getE() 110 { 111 int i,j;Mat c; 112 for(i=0;i<61;i++) 113 for(j=0;j<61;j++) 114 c.a[i][j]=(i==j); 115 return c; 116 } 117 118 Mat solve(Mat a,int k) 119 { 120 Mat res=e; 121 all=1;int b=26; 122 while(k) 123 { 124 if(k&1) 125 { 126 res=mulPow(res,a); 127 all*=b; 128 if(all>=mod) 129 all%=mod; 130 } 131 a=mulPow(a,a); 132 b=b*b; 133 if(b>=mod) 134 b%=mod; 135 k=k>>1; 136 } 137 return res; 138 } 139 140 int main() 141 { 142 int i,j,k,temp;e=getE(); 143 //freopen("D:\\in.txt","r",stdin); 144 while(scanf("%d%d",&n,&m)==2) 145 { 146 num=1; 147 memset(root,0,sizeof(struct node)); 148 for(i=0;i<n;i++) 149 { 150 scanf("%*c%s",str); 151 insert(str); 152 } 153 add_Fail(); 154 Mat res; 155 int id=0,id1; 156 for(i=0;i<num;i++) 157 { 158 if(root[i].cnt==0) 159 { 160 id1=0; 161 for(j=0;j<num;j++) 162 { 163 if(!root[j].cnt) 164 { 165 int cc=0; 166 for(k=0;k<26;k++) 167 { 168 if(root[j].jump[k]==root+i) 169 cc++; 170 } 171 res.a[id][id1]=cc; 172 id1++; 173 } 174 } 175 id++; 176 } 177 } 178 len=id; 179 all=1; 180 res=solve(res,m); 181 temp=0; 182 for(i=0;i<len;i++) 183 { 184 temp=(temp+res.a[i][0]); 185 if(temp>=mod) 186 temp%=mod; 187 } 188 all=all-temp; 189 if(all<0) 190 all+=mod; 191 printf("%d\n",all); 192 } 193 return 0; 194 }