转自kuangbin的AC自动机(赛前最后一博)
有了KMP和Trie的基础,就可以学习神奇的AC自动机了。AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配。
AC自动机 其实 就是创建了一个状态的转移图,思想很重要。
推荐的学习链接:
http://acm.uestc.edu.cn/bbs/read.php?tid=4294
http://blog.csdn.net/niushuai666/article/details/7002823
http://hi.baidu.com/nialv7/item/ce1ce015d44a6ba7feded52d
AC自动机专题训练链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=25605#overview 这里我提交的代码是公开的,可以看到
题目来源:http://www.notonlysuccess.com/index.php/aho-corasick-automaton/
写AC自动机的代码风格是向昀神学的,好简洁,写起来好棒的感觉。
1、HDU 2222 Keywords Search 最基本的入门题了
就是求目标串中出现了几个模式串。
很基础了。使用一个int型的end数组记录,查询一次。
//====================== // HDU 2222 // 求目标串中出现了几个模式串 //==================== #include <stdio.h> #include <algorithm> #include <iostream> #include <string.h> #include <queue> using namespace std;struct Trie {int next[500010][26],fail[500010],end[500010];int root,L;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();}void insert(char buf[]){int len = strlen(buf);int now = root;for(int i = 0;i < len;i++){if(next[now][buf[i]-'a'] == -1)next[now][buf[i]-'a'] = newnode();now = next[now][buf[i]-'a'];}end[now]++;}void build(){queue<int>Q;fail[root] = root;for(int i = 0;i < 26;i++)if(next[root][i] == -1)next[root][i] = root;else{fail[next[root][i]] = root;Q.push(next[root][i]);}while( !Q.empty() ){int now = Q.front();Q.pop();for(int i = 0;i < 26;i++)if(next[now][i] == -1)next[now][i] = next[fail[now]][i];else{fail[next[now][i]]=next[fail[now]][i];Q.push(next[now][i]);}}}int query(char buf[]){int len = strlen(buf);int now = root;int res = 0;for(int i = 0;i < len;i++){now = next[now][buf[i]-'a'];int temp = now;while( temp != root ){res += end[temp];end[temp] = 0;temp = fail[temp];}}return res;}void debug(){for(int i = 0;i < L;i++){printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);for(int j = 0;j < 26;j++)printf("%2d",next[i][j]);printf("]\n");}} }; char buf[1000010]; Trie ac; int main() {int T;int n;scanf("%d",&T);while( T-- ){scanf("%d",&n);ac.init();for(int i = 0;i < n;i++){scanf("%s",buf);ac.insert(buf);}ac.build();scanf("%s",buf);printf("%d\n",ac.query(buf));}return 0; }
2、HDU 2896 病毒侵袭
这题和上题差不多,要输出出现模式串的id,用end记录id就可以了。还有trie树的分支是128的
题解here
//============================================================================ // Name : HDU.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <queue> using namespace std;struct Trie {int next[210*500][128],fail[210*500],end[210*500];int root,L;int newnode(){for(int i = 0;i < 128;i++)next[L][i] = -1;end[L++] = -1;return L-1;}void init(){L = 0;root = newnode();}void insert(char s[],int id){int len = strlen(s);int now = root;for(int i = 0;i < len;i++){if(next[now][s[i]] == -1)next[now][s[i]] = newnode();now=next[now][s[i]];}end[now]=id;}void build(){queue<int>Q;fail[root] = root;for(int i = 0;i < 128;i++)if(next[root][i] == -1)next[root][i] = root;else{fail[next[root][i]] = root;Q.push(next[root][i]);}while(!Q.empty()){int now = Q.front();Q.pop();for(int i = 0;i < 128;i++)if(next[now][i] == -1)next[now][i] = next[fail[now]][i];else{fail[next[now][i]] = next[fail[now]][i];Q.push(next[now][i]);}}}bool used[510];bool query(char buf[],int n,int id){int len = strlen(buf);int now = root;memset(used,false,sizeof(used));bool flag = false;for(int i = 0;i < len;i++){now = next[now][buf[i]];int temp = now;while(temp != root){if(end[temp] != -1){used[end[temp]] = true;flag = true;}temp = fail[temp];}}if(!flag)return false;printf("web %d:",id);for(int i = 1;i <= n;i++)if(used[i])printf(" %d",i);printf("\n");return true;} }; char buf[10010]; Trie ac; int main() {int n,m;while(scanf("%d",&n) != EOF){ac.init();for(int i = 1;i <= n;i++){scanf("%s",buf);ac.insert(buf,i);}ac.build();int ans = 0;scanf("%d",&m);for(int i = 1;i <= m;i++){scanf("%s",buf);if(ac.query(buf,n,i))ans++;}printf("total: %d\n",ans);}return 0; }
View Code
3、HDU 3065 病毒侵袭持续中
这题的变化也不大,就是需要输出每个模式串出现的次数,查询的时候使用一个数组进行记录就可以了
1 //============================================================================ 2 // Name : HDU.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <stdio.h> 11 #include <string.h> 12 #include <algorithm> 13 #include <queue> 14 using namespace std; 15 16 char str[1010][100]; 17 struct Trie 18 { 19 int next[1010*50][128],fail[1010*50],end[1010*50]; 20 int root,L; 21 int newnode() 22 { 23 for(int i = 0;i < 128;i++) 24 next[L][i] = -1; 25 end[L++] = -1; 26 return L-1; 27 } 28 void init() 29 { 30 L = 0; 31 root = newnode(); 32 } 33 void insert(char s[],int id) 34 { 35 int len = strlen(s); 36 int now = root; 37 for(int i = 0;i < len;i++) 38 { 39 if(next[now][s[i]] == -1) 40 next[now][s[i]] = newnode(); 41 now = next[now][s[i]]; 42 } 43 end[now] = id; 44 } 45 void build() 46 { 47 queue<int>Q; 48 fail[root] = root; 49 for(int i = 0;i < 128;i++) 50 if(next[root][i] == -1) 51 next[root][i] = root; 52 else 53 { 54 fail[next[root][i]] = root; 55 Q.push(next[root][i]); 56 } 57 while(!Q.empty()) 58 { 59 int now = Q.front(); 60 Q.pop(); 61 for(int i = 0;i < 128;i++) 62 if(next[now][i] == -1) 63 next[now][i]=next[fail[now]][i]; 64 else 65 { 66 fail[next[now][i]]=next[fail[now]][i]; 67 Q.push(next[now][i]); 68 } 69 } 70 } 71 int num[1010]; 72 void query(char buf[],int n) 73 { 74 for(int i = 0;i < n;i++) 75 num[i] = 0; 76 int len=strlen(buf); 77 int now=root; 78 for(int i=0;i<len;i++) 79 { 80 now=next[now][buf[i]]; 81 int temp = now; 82 while( temp != root ) 83 { 84 if(end[temp] != -1) 85 num[end[temp]]++; 86 temp = fail[temp]; 87 } 88 } 89 for(int i = 0;i < n;i++) 90 if(num[i] > 0) 91 printf("%s: %d\n",str[i],num[i]); 92 } 93 94 }; 95 96 char buf[2000010]; 97 Trie ac; 98 void debug() 99 { 100 for (int i = 0; i < ac.L; i++) 101 { 102 printf("id = %3d ,fail = %3d ,end = %3d, chi = [",i,ac.fail[i],ac.end[i]); 103 for (int j = 0; j < 128; j++) 104 printf("%2d ",ac.next[i][j]); 105 printf("]\n"); 106 } 107 } 108 int main() 109 { 110 // freopen("in.txt","r",stdin); 111 // freopen("out.txt","w",stdout); 112 int n; 113 while(scanf("%d",&n) == 1) 114 { 115 ac.init(); 116 for(int i = 0;i < n;i++) 117 { 118 scanf("%s",str[i]); 119 ac.insert(str[i],i); 120 } 121 ac.build(); 122 scanf("%s",buf); 123 ac.query(buf,n); 124 } 125 return 0; 126 }
View Code
4、ZOJ 3430 Detect the Virus
主要是解码过程,解码以后就是模板题了。
求出现的模式串的种类数
分支需要256个
1 //============================================================================ 2 // Name : ZOJ.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <stdio.h> 11 #include <string.h> 12 #include <algorithm> 13 #include <queue> 14 using namespace std; 15 16 struct Trie 17 { 18 int next[520*64][256],fail[520*64],end[520*64]; 19 int root,L; 20 int newnode() 21 { 22 for(int i = 0;i < 256;i++) 23 next[L][i] = -1; 24 end[L++] = -1; 25 return L-1; 26 } 27 void init() 28 { 29 L = 0; 30 root = newnode(); 31 } 32 void insert(unsigned char buf[],int len,int id) 33 { 34 int now = root; 35 for(int i = 0;i < len;i++) 36 { 37 if(next[now][buf[i]] == -1) 38 next[now][buf[i]] = newnode(); 39 now = next[now][buf[i]]; 40 } 41 end[now] = id; 42 } 43 void build() 44 { 45 queue<int>Q; 46 fail[root] = root; 47 for(int i = 0;i < 256;i++) 48 if(next[root][i] == -1) 49 next[root][i] = root; 50 else 51 { 52 fail[next[root][i]]=root; 53 Q.push(next[root][i]); 54 } 55 while(!Q.empty()) 56 { 57 int now = Q.front(); 58 Q.pop(); 59 for(int i = 0;i < 256;i++) 60 if(next[now][i] == -1) 61 next[now][i] = next[fail[now]][i]; 62 else 63 { 64 fail[next[now][i]] = next[fail[now]][i]; 65 Q.push(next[now][i]); 66 } 67 } 68 } 69 bool used[520]; 70 int query(unsigned char buf[],int len,int n) 71 { 72 memset(used,false,sizeof(used)); 73 int now = root; 74 for(int i = 0;i < len;i++) 75 { 76 now = next[now][buf[i]]; 77 int temp = now; 78 while( temp!=root ) 79 { 80 if(end[temp] != -1) 81 used[end[temp]]=true; 82 temp = fail[temp]; 83 } 84 } 85 int res = 0; 86 for(int i = 0;i < n;i++) 87 if(used[i]) 88 res++; 89 return res; 90 } 91 }; 92 93 unsigned char buf[2050]; 94 int tot; 95 char str[4000]; 96 unsigned char s[4000]; 97 unsigned char Get(char ch) 98 { 99 if( ch>='A'&&ch<='Z' )return ch-'A'; 100 if( ch>='a'&&ch<='z' )return ch-'a'+26; 101 if( ch>='0'&&ch<='9' )return ch-'0'+52; 102 if( ch=='+' )return 62; 103 else return 63; 104 } 105 void change(unsigned char str[],int len) 106 { 107 int t=0; 108 for(int i=0;i<len;i+=4) 109 { 110 buf[t++]=((str[i]<<2)|(str[i+1]>>4)); 111 if(i+2 < len) 112 buf[t++]=( (str[i+1]<<4)|(str[i+2]>>2) ); 113 if(i+3 < len) 114 buf[t++]= ( (str[i+2]<<6)|str[i+3] ); 115 } 116 tot=t; 117 } 118 Trie ac; 119 int main() 120 { 121 // freopen("in.txt","r",stdin); 122 // freopen("out.txt","w",stdout); 123 int n,m; 124 while(scanf("%d",&n) == 1) 125 { 126 ac.init(); 127 for(int i = 0;i < n;i++) 128 { 129 scanf("%s",str); 130 int len = strlen(str); 131 while(str[len-1]=='=')len--; 132 for(int j = 0;j < len;j++) 133 { 134 s[j] = Get(str[j]); 135 } 136 change(s,len); 137 ac.insert(buf,tot,i); 138 } 139 ac.build(); 140 scanf("%d",&m); 141 while(m--) 142 { 143 scanf("%s",str); 144 int len=strlen(str); 145 while(str[len-1]=='=')len--; 146 for(int j = 0;j < len;j++) 147 s[j] = Get(str[j]); 148 change(s,len); 149 printf("%d\n",ac.query(buf,tot,n)); 150 } 151 printf("\n"); 152 } 153 return 0; 154 }
View Code
5、POJ 2778 DNA Sequence
AC自动机+矩阵加速
这个时候AC自动机 的一种状态转移图的思路就很透彻了。
AC自动机就是可以确定状态的转移。
1 //============================================================================ 2 // Name : POJ.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <stdio.h> 11 #include <algorithm> 12 #include <string.h> 13 #include <queue> 14 using namespace std; 15 16 const int MOD=100000; 17 struct Matrix 18 { 19 int mat[110][110],n; 20 Matrix(){} 21 Matrix(int _n) 22 { 23 n = _n; 24 for(int i=0;i<n;i++) 25 for(int j=0;j<n;j++) 26 mat[i][j]=0; 27 } 28 Matrix operator *(const Matrix &b)const 29 { 30 Matrix ret=Matrix(n); 31 for(int i=0;i<n;i++) 32 for(int j=0;j<n;j++) 33 for(int k=0;k<n;k++) 34 { 35 int tmp=(long long)mat[i][k]*b.mat[k][j]%MOD; 36 ret.mat[i][j]=(ret.mat[i][j]+tmp)%MOD; 37 } 38 return ret; 39 } 40 }; 41 struct Trie 42 { 43 int next[110][4],fail[110]; 44 bool end[110]; 45 int root,L; 46 int newnode() 47 { 48 for(int i=0;i<4;i++) 49 next[L][i]=-1; 50 end[L++]=false; 51 return L-1; 52 } 53 void init() 54 { 55 L=0; 56 root=newnode(); 57 } 58 int getch(char ch) 59 { 60 switch(ch) 61 { 62 case 'A': 63 return 0; 64 break; 65 case 'C': 66 return 1; 67 break; 68 case 'G': 69 return 2; 70 break; 71 case 'T': 72 return 3; 73 break; 74 } 75 } 76 void insert(char s[]) 77 { 78 int len=strlen(s); 79 int now=root; 80 for(int i = 0;i < len;i++) 81 { 82 if(next[now][getch(s[i])] == -1) 83 next[now][getch(s[i])] = newnode(); 84 now = next[now][getch(s[i])]; 85 } 86 end[now]=true; 87 } 88 void build() 89 { 90 queue<int>Q; 91 for(int i = 0;i < 4;i++) 92 if(next[root][i] == -1) 93 next[root][i] = root; 94 else 95 { 96 fail[next[root][i]] = root; 97 Q.push(next[root][i]); 98 } 99 while(!Q.empty()) 100 { 101 int now = Q.front(); 102 Q.pop(); 103 if(end[fail[now]]==true) 104 end[now]=true; 105 for(int i = 0;i < 4;i++) 106 { 107 if(next[now][i] == -1) 108 next[now][i] = next[fail[now]][i]; 109 else 110 { 111 fail[next[now][i]] = next[fail[now]][i]; 112 Q.push(next[now][i]); 113 } 114 } 115 } 116 } 117 Matrix getMatrix() 118 { 119 Matrix res = Matrix(L); 120 for(int i=0;i<L;i++) 121 for(int j=0;j<4;j++) 122 if(end[next[i][j]]==false) 123 res.mat[i][next[i][j]]++; 124 return res; 125 } 126 }; 127 128 Trie ac; 129 char buf[20]; 130 131 Matrix pow_M(Matrix a,int n) 132 { 133 Matrix ret = Matrix(a.n); 134 for(int i = 0; i < ret.n; i++) 135 ret.mat[i][i]=1; 136 Matrix tmp=a; 137 while(n) 138 { 139 if(n&1)ret=ret*tmp; 140 tmp=tmp*tmp; 141 n>>=1; 142 } 143 return ret; 144 } 145 146 int main() 147 { 148 int n,m; 149 while(scanf("%d%d",&n,&m) != EOF) 150 { 151 ac.init(); 152 for(int i=0;i<n;i++) 153 { 154 scanf("%s",buf); 155 ac.insert(buf); 156 } 157 ac.build(); 158 Matrix a=ac.getMatrix(); 159 a=pow_M(a,m); 160 int ans=0; 161 for(int i=0;i<a.n;i++) 162 { 163 ans=(ans+a.mat[0][i])%MOD; 164 } 165 printf("%d\n",ans); 166 } 167 return 0; 168 }
View Code
6、HDU 2243 考研路茫茫——单词情结
这题和上题有些类似。但是需要求和。
所以给
矩阵增加一维,这样可以完美解决
题解here
1 //============================================================================ 2 // Name : HDU.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <stdio.h> 11 #include <string.h> 12 #include <algorithm> 13 #include <queue> 14 using namespace std; 15 struct Matrix 16 { 17 unsigned long long mat[40][40]; 18 int n; 19 Matrix(){} 20 Matrix(int _n) 21 { 22 n=_n; 23 for(int i=0;i<n;i++) 24 for(int j=0;j<n;j++) 25 mat[i][j] = 0; 26 } 27 Matrix operator *(const Matrix &b)const 28 { 29 Matrix ret = Matrix(n); 30 for(int i=0;i<n;i++) 31 for(int j=0;j<n;j++) 32 for(int k=0;k<n;k++) 33 ret.mat[i][j]+=mat[i][k]*b.mat[k][j]; 34 return ret; 35 } 36 }; 37 unsigned long long pow_m(unsigned long long a,int n) 38 { 39 unsigned long long ret=1; 40 unsigned long long tmp = a; 41 while(n) 42 { 43 if(n&1)ret*=tmp; 44 tmp*=tmp; 45 n>>=1; 46 } 47 return ret; 48 } 49 Matrix pow_M(Matrix a,int n) 50 { 51 Matrix ret = Matrix(a.n); 52 for(int i=0;i<a.n;i++) 53 ret.mat[i][i] = 1; 54 Matrix tmp = a; 55 while(n) 56 { 57 if(n&1)ret=ret*tmp; 58 tmp=tmp*tmp; 59 n>>=1; 60 } 61 return ret; 62 } 63 struct Trie 64 { 65 int next[40][26],fail[40]; 66 bool end[40]; 67 int root,L; 68 int newnode() 69 { 70 for(int i = 0;i < 26;i++) 71 next[L][i] = -1; 72 end[L++] = false; 73 return L-1; 74 } 75 void init() 76 { 77 L = 0; 78 root = newnode(); 79 } 80 void insert(char buf[]) 81 { 82 int len = strlen(buf); 83 int now = root; 84 for(int i = 0;i < len;i++) 85 { 86 if(next[now][buf[i]-'a'] == -1) 87 next[now][buf[i]-'a'] = newnode(); 88 now = next[now][buf[i]-'a']; 89 } 90 end[now] = true; 91 } 92 void build() 93 { 94 queue<int>Q; 95 fail[root]=root; 96 for(int i = 0;i < 26;i++) 97 if(next[root][i] == -1) 98 next[root][i] = root; 99 else 100 { 101 fail[next[root][i]] = root; 102 Q.push(next[root][i]); 103 } 104 while(!Q.empty()) 105 { 106 int now = Q.front(); 107 Q.pop(); 108 if(end[fail[now]])end[now]=true; 109 for(int i = 0;i < 26;i++) 110 if(next[now][i] == -1) 111 next[now][i] = next[fail[now]][i]; 112 else 113 { 114 fail[next[now][i]] = next[fail[now]][i]; 115 Q.push(next[now][i]); 116 } 117 } 118 } 119 Matrix getMatrix() 120 { 121 Matrix ret = Matrix(L+1); 122 for(int i = 0;i < L;i++) 123 for(int j = 0;j < 26;j++) 124 if(end[next[i][j]]==false) 125 ret.mat[i][next[i][j]] ++; 126 for(int i = 0;i < L+1;i++) 127 ret.mat[i][L] = 1; 128 return ret; 129 } 130 void debug() 131 { 132 for(int i = 0;i < L;i++) 133 { 134 printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]); 135 for(int j = 0;j < 26;j++) 136 printf("%2d",next[i][j]); 137 printf("]\n"); 138 } 139 } 140 }; 141 char buf[10]; 142 Trie ac; 143 int main() 144 { 145 // freopen("in.txt","r",stdin); 146 // freopen("out.txt","w",stdout); 147 int n,L; 148 while(scanf("%d%d",&n,&L)==2) 149 { 150 ac.init(); 151 for(int i = 0;i < n;i++) 152 { 153 scanf("%s",buf); 154 ac.insert(buf); 155 } 156 ac.build(); 157 Matrix a = ac.getMatrix(); 158 a = pow_M(a,L); 159 unsigned long long res = 0; 160 for(int i = 0;i < a.n;i++) 161 res += a.mat[0][i]; 162 res--; 163 164 /* 165 * f[n]=1 + 26^1 + 26^2 +...26^n 166 * f[n]=26*f[n-1]+1 167 * {f[n] 1} = {f[n-1] 1}[26 0;1 1] 168 * 数是f[L]-1; 169 * 此题的L<2^31.矩阵的幂不能是L+1次,否则就超时了 170 */ 171 a = Matrix(2); 172 a.mat[0][0]=26; 173 a.mat[1][0] = a.mat[1][1] = 1; 174 a=pow_M(a,L); 175 unsigned long long ans=a.mat[1][0]+a.mat[0][0]; 176 ans--; 177 ans-=res; 178 cout<<ans<<endl; 179 } 180 return 0; 181 }
View Code
7、POJ 1625 Censored!
AC自动机+DP+高精度
好题
题解here
//============================================================================ // Name : POJ.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include <queue> #include <map> using namespace std; map<char,int>mp; int N,M,P; struct Matrix {int mat[110][110];int n;Matrix(){}Matrix(int _n){n=_n;for(int i = 0;i < n;i++)for(int j = 0;j < n;j++)mat[i][j] = 0;} }; struct Trie {int next[110][256],fail[110];bool end[110];int L,root;int newnode(){for(int i = 0;i < 256;i++)next[L][i] = -1;end[L++] = false;return L-1;}void init(){L = 0;root = newnode();}void insert(char buf[]){int len = strlen(buf);int now = root;for(int i = 0;i < len;i++){if(next[now][mp[buf[i]]] == -1)next[now][mp[buf[i]]] = newnode();now = next[now][mp[buf[i]]];}end[now] = true;}void build(){queue<int>Q;fail[root] = root;for(int i = 0;i < 256;i++)if(next[root][i] == -1)next[root][i] = root;else{fail[next[root][i]] = root;Q.push(next[root][i]);}while(!Q.empty()){int now = Q.front();Q.pop();if(end[fail[now]]==true)end[now]=true;for(int i = 0;i < 256;i++)if(next[now][i] == -1)next[now][i] = next[fail[now]][i];else{fail[next[now][i]] = next[fail[now]][i];Q.push(next[now][i]);}}}Matrix getMatrix(){Matrix res = Matrix(L);for(int i = 0;i < L;i++)for(int j = 0;j < N;j++)if(end[next[i][j]]==false)res.mat[i][next[i][j]]++;return res;}void debug(){for(int i = 0;i < L;i++){printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);for(int j = 0;j < 26;j++)printf("%2d",next[i][j]);printf("]\n");}}};/** 高精度,支持乘法和加法*/ struct BigInt {const static int mod = 10000;const static int DLEN = 4;int a[600],len;BigInt(){memset(a,0,sizeof(a));len = 1;}BigInt(int v){memset(a,0,sizeof(a));len = 0;do{a[len++] = v%mod;v /= mod;}while(v);}BigInt(const char s[]){memset(a,0,sizeof(a));int L = strlen(s);len = L/DLEN;if(L%DLEN)len++;int index = 0;for(int i = L-1;i >= 0;i -= DLEN){int t = 0;int k = i - DLEN + 1;if(k < 0)k = 0;for(int j = k;j <= i;j++)t = t*10 + s[j] - '0';a[index++] = t;}}BigInt operator +(const BigInt &b)const{BigInt res;res.len = max(len,b.len);for(int i = 0;i <= res.len;i++)res.a[i] = 0;for(int i = 0;i < res.len;i++){res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0);res.a[i+1] += res.a[i]/mod;res.a[i] %= mod;}if(res.a[res.len] > 0)res.len++;return res;}BigInt operator *(const BigInt &b)const{BigInt res;for(int i = 0; i < len;i++){int up = 0;for(int j = 0;j < b.len;j++){int temp = a[i]*b.a[j] + res.a[i+j] + up;res.a[i+j] = temp%mod;up = temp/mod;}if(up != 0)res.a[i + b.len] = up;}res.len = len + b.len;while(res.a[res.len - 1] == 0 &&res.len > 1)res.len--;return res;}void output(){printf("%d",a[len-1]);for(int i = len-2;i >=0 ;i--)printf("%04d",a[i]);printf("\n");} }; char buf[1010]; BigInt dp[2][110]; Trie ac; int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout);while(scanf("%d%d%d",&N,&M,&P)==3){gets(buf);gets(buf);mp.clear();int len = strlen(buf);for(int i = 0;i < len;i++)mp[buf[i]]=i;ac.init();for(int i = 0;i < P;i++){gets(buf);ac.insert(buf);}ac.build(); // ac.debug();Matrix a= ac.getMatrix();// for(int i = 0;i <a.n;i++) // { // for(int j=0;j<a.n;j++)printf("%d ",a.mat[i][j]); // cout<<endl; // }int now = 0;dp[now][0] = 1;for(int i = 1;i < a.n;i++)dp[now][i] = 0;for(int i = 0;i < M;i++){now^=1;for(int j = 0;j < a.n;j++)dp[now][j] = 0;for(int j = 0;j < a.n;j++)for(int k = 0;k < a.n;k++)if(a.mat[j][k] > 0)dp[now][k] = dp[now][k]+dp[now^1][j]*a.mat[j][k]; // for(int j = 0;j < a.n;j++) // dp[now][j].output(); }BigInt ans = 0;for(int i = 0;i < a.n;i++)ans = ans + dp[now][i];ans.output();}return 0; }
View Code
8、HDU 2825 Wireless Password
AC自动机+状态压缩DP
相当于在AC自动机上产生状态转移,然后进行dp
//============================================================================ // Name : HDU.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> using namespace std; const int MOD=20090717; int n,m,k; int dp[30][110][1<<10]; int num[5000];struct Trie {int next[110][26],fail[110],end[110];int root,L;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();}void insert(char buf[],int id){int len = strlen(buf);int now = root;for(int i = 0;i < len;i++){if(next[now][buf[i]-'a']==-1)next[now][buf[i]-'a'] = newnode();now = next[now][buf[i]-'a'];}end[now] |= (1<<id);}void build(){queue<int>Q;fail[root] = root;for(int i = 0;i < 26;i++)if(next[root][i] == -1)next[root][i] = root;else{fail[next[root][i]] = root;Q.push(next[root][i]);}while(!Q.empty()){int now = Q.front();Q.pop();end[now] |= end[fail[now]];for(int i = 0;i < 26;i++)if(next[now][i] == -1)next[now][i] = next[fail[now]][i];else{fail[next[now][i]] = next[fail[now]][i];Q.push(next[now][i]);}}}int solve(){//memset(dp,0,sizeof(dp));for(int i = 0;i <= n;i++)for(int j = 0;j < L;j++)for(int p = 0;p < (1<<m);p++)dp[i][j][p]=0;dp[0][0][0] = 1;for(int i = 0;i < n;i++)for(int j = 0;j < L;j++)for(int p = 0;p< (1<<m);p++)if(dp[i][j][p] > 0){for(int x = 0;x < 26;x++){int newi = i+1;int newj = next[j][x];int newp = (p|end[newj]);dp[newi][newj][newp] += dp[i][j][p];dp[newi][newj][newp]%=MOD;}}int ans = 0;for(int p = 0;p < (1<<m);p++){if(num[p] < k)continue;for(int i = 0;i < L;i++){ans = (ans + dp[n][i][p])%MOD;}}return ans;} }; char buf[20]; Trie ac; int main() {for(int i=0;i<(1<<10);i++){num[i] = 0;for(int j = 0;j < 10;j++)if(i & (1<<j))num[i]++;}while(scanf("%d%d%d",&n,&m,&k)==3){if(n== 0 && m==0 &&k==0)break;ac.init();for(int i = 0;i < m;i++){scanf("%s",buf);ac.insert(buf,i);}ac.build();printf("%d\n",ac.solve());}return 0; }
View Code
9、HDU 2296 Ring
需要输出字典序最小的解
在DP的时候加一个字符数组来记录就行了
//============================================================================ // Name : HDU.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <queue> using namespace std;int a[110]; int dp[55][1110]; char str[55][1110][55];bool cmp(char s1[],char s2[]) {int len1=strlen(s1);int len2=strlen(s2);if(len1 != len2)return len1 < len2;else return strcmp(s1,s2) < 0; }const int INF=0x3f3f3f3f; struct Trie {int next[1110][26],fail[1110],end[1110];int root,L;int newnode(){for(int i = 0;i < 26;i++)next[L][i] = -1;end[L++] = -1;return L-1;}void init(){L = 0;root = newnode();}void insert(char buf[],int id){int len = strlen(buf);int now = root;for(int i = 0;i < len;i++){if(next[now][buf[i]-'a'] == -1)next[now][buf[i]-'a'] = newnode();now = next[now][buf[i]-'a'];}end[now] = id;}void build(){queue<int>Q;fail[root] = root;for(int i = 0;i < 26;i++)if(next[root][i] == -1)next[root][i] = root;else{fail[next[root][i]] = root;Q.push(next[root][i]);}while(!Q.empty()){int now = Q.front();Q.pop();for(int i = 0;i < 26;i++)if(next[now][i] == -1)next[now][i] = next[fail[now]][i];else{fail[next[now][i]] = next[fail[now]][i];Q.push(next[now][i]);}}}void solve(int n){for(int i = 0;i <= n;i++)for(int j = 0;j < L;j++)dp[i][j] = -INF;dp[0][0] = 0;strcpy(str[0][0],"");char ans[55];strcpy(ans,"");int Max = 0;char tmp[55];for(int i = 0; i < n;i++)for(int j = 0;j < L;j++)if(dp[i][j]>=0){strcpy(tmp,str[i][j]);int len = strlen(tmp);for(int k = 0;k < 26;k++){int nxt=next[j][k];tmp[len] = 'a'+k;tmp[len+1] = 0;int tt = dp[i][j];if(end[nxt] != -1)tt+=a[end[nxt]];if(dp[i+1][nxt]<tt || (dp[i+1][nxt]==tt && cmp(tmp,str[i+1][nxt]))){dp[i+1][nxt] = tt;strcpy(str[i+1][nxt],tmp);if(tt > Max ||(tt==Max && cmp(tmp,ans))){Max = tt;strcpy(ans,tmp);}}}}printf("%s\n",ans);} }; char buf[60]; Trie ac; int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout);int T;int n,m;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);ac.init();for(int i = 0;i < m;i++){scanf("%s",buf);ac.insert(buf,i);}for(int i = 0;i < m;i++)scanf("%d",&a[i]);ac.build();ac.solve(n);}return 0; }
View Code
10、HDU 2457 DNA repair
很简单的AC自动机+DP了
1 //============================================================================ 2 // Name : HDU.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <string.h> 11 #include <stdio.h> 12 #include <algorithm> 13 #include <queue> 14 using namespace std; 15 const int INF = 0x3f3f3f3f; 16 struct Trie 17 { 18 int next[1010][4],fail[1010]; 19 bool end[1010]; 20 int root,L; 21 int newnode() 22 { 23 for(int i = 0;i < 4;i++) 24 next[L][i] = -1; 25 end[L++] = false; 26 return L-1; 27 } 28 void init() 29 { 30 L = 0; 31 root = newnode(); 32 } 33 int getch(char ch) 34 { 35 if(ch == 'A')return 0; 36 else if(ch == 'C')return 1; 37 else if(ch == 'G')return 2; 38 else if(ch == 'T')return 3; 39 } 40 void insert(char buf[]) 41 { 42 int len = strlen(buf); 43 int now = root; 44 for(int i = 0;i < len;i++) 45 { 46 if(next[now][getch(buf[i])] == -1) 47 next[now][getch(buf[i])] = newnode(); 48 now = next[now][getch(buf[i])]; 49 } 50 end[now] = true; 51 } 52 void build() 53 { 54 queue<int>Q; 55 fail[root] = root; 56 for(int i = 0;i < 4;i++) 57 if(next[root][i] == -1) 58 next[root][i] = root; 59 else 60 { 61 fail[next[root][i]] = root; 62 Q.push(next[root][i]); 63 } 64 while(!Q.empty()) 65 { 66 int now = Q.front(); 67 Q.pop(); 68 if(end[fail[now]])end[now] = true;//这里不要忘记 69 for(int i = 0;i < 4;i++) 70 if(next[now][i] == -1) 71 next[now][i] = next[fail[now]][i]; 72 else 73 { 74 fail[next[now][i]] = next[fail[now]][i]; 75 Q.push(next[now][i]); 76 } 77 } 78 } 79 int dp[1010][1010]; 80 int solve(char buf[]) 81 { 82 int len = strlen(buf); 83 for(int i = 0;i <= len;i++) 84 for(int j = 0;j < L;j++) 85 dp[i][j] = INF; 86 dp[0][root] = 0; 87 for(int i = 0;i < len;i++) 88 for(int j = 0;j < L;j++) 89 if(dp[i][j] < INF) 90 { 91 for(int k = 0;k < 4;k++) 92 { 93 int news = next[j][k]; 94 if(end[news])continue; 95 int tmp; 96 if( k == getch(buf[i]))tmp = dp[i][j]; 97 else tmp = dp[i][j] + 1; 98 dp[i+1][news] = min(dp[i+1][news],tmp); 99 } 100 } 101 int ans = INF; 102 for(int j = 0;j < L;j++) 103 ans = min(ans,dp[len][j]); 104 if(ans == INF)ans = -1; 105 return ans; 106 } 107 108 }; 109 char buf[1010]; 110 Trie ac; 111 int main() 112 { 113 int n; 114 int iCase = 0; 115 while ( scanf("%d",&n) == 1 && n) 116 { 117 iCase++; 118 ac.init(); 119 while(n--) 120 { 121 scanf("%s",buf); 122 ac.insert(buf); 123 } 124 ac.build(); 125 scanf("%s",buf); 126 printf("Case %d: %d\n",iCase,ac.solve(buf)); 127 } 128 return 0; 129 }
View Code
11、ZOJ 3228 Searching the String
这题需要查询两种,一种是可重叠,一种是不可重叠的。
找模式串在目标串中的出现次数。
加一个数组记录上一次出现的位置,然后就可以求出不可重叠的了
1 //============================================================================ 2 // Name : ZOJ.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <stdio.h> 11 #include <string.h> 12 #include <algorithm> 13 #include <queue> 14 using namespace std; 15 16 struct Trie 17 { 18 int next[600010][26],fail[600010],deep[600010]; 19 int root,L; 20 int newnode() 21 { 22 for(int i = 0;i < 26;i++) 23 next[L][i] = -1; 24 L++; 25 return L-1; 26 } 27 void init() 28 { 29 L = 0; 30 root = newnode(); 31 deep[root] = 0; 32 } 33 int insert(char buf[]) 34 { 35 int len = strlen(buf); 36 int now = root; 37 for(int i = 0;i < len;i++) 38 { 39 if(next[now][buf[i]-'a'] == -1) 40 { 41 next[now][buf[i]-'a'] = newnode(); 42 deep[ next[now][buf[i]-'a'] ] = i+1; 43 } 44 now = next[now][buf[i]-'a']; 45 } 46 return now; 47 } 48 void build() 49 { 50 queue<int>Q; 51 fail[root] = root; 52 for(int i = 0;i < 26;i++) 53 if(next[root][i] == -1) 54 next[root][i] = root; 55 else 56 { 57 fail[next[root][i]] = root; 58 Q.push(next[root][i]); 59 } 60 while(!Q.empty()) 61 { 62 int now = Q.front(); 63 Q.pop(); 64 for(int i = 0;i < 26;i++) 65 if(next[now][i] == -1) 66 next[now][i] = next[fail[now]][i]; 67 else 68 { 69 fail[next[now][i]] = next[fail[now]][i]; 70 Q.push(next[now][i]); 71 } 72 } 73 } 74 int cnt[600010][2]; 75 int last[600010]; 76 void query(char buf[]) 77 { 78 int len = strlen(buf); 79 int now = root; 80 memset(cnt,0,sizeof(cnt)); 81 memset(last,-1,sizeof(last)); 82 for(int i = 0;i < len;i++) 83 { 84 now = next[now][buf[i]-'a']; 85 int temp = now; 86 while(temp != root) 87 { 88 cnt[temp][0]++; 89 if(i - last[temp] >= deep[temp]) 90 { 91 last[temp] = i; 92 cnt[temp][1]++; 93 } 94 temp = fail[temp]; 95 } 96 } 97 } 98 }; 99 Trie ac; 100 char str[100010]; 101 char buf[20]; 102 int typ[100010],pos[100010]; 103 int main() 104 { 105 // freopen("in.txt","r",stdin); 106 // freopen("out.txt","w",stdout); 107 int n; 108 int iCase = 0; 109 while(scanf("%s",str)==1) 110 { 111 iCase++; 112 printf("Case %d\n",iCase); 113 scanf("%d",&n); 114 ac.init(); 115 for(int i = 0;i < n;i++) 116 { 117 scanf("%d%s",&typ[i],buf); 118 pos[i]=ac.insert(buf); 119 } 120 ac.build(); 121 ac.query(str); 122 for(int i = 0;i < n;i++) 123 printf("%d\n",ac.cnt[pos[i]][typ[i]]); 124 printf("\n"); 125 } 126 return 0; 127 }
View Code
12、HDU 3341 Lost's revenge
这题主要是状态的表示,就是记录ACGT出现的次数。
然后这个ACGT次数表示的时候,状态要转化。
题解here
1 //============================================================================ 2 // Name : HDU.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <string.h> 11 #include <stdio.h> 12 #include <algorithm> 13 #include <queue> 14 using namespace std; 15 const int INF = 0x3f3f3f3f; 16 struct Trie 17 { 18 int next[510][4],fail[510]; 19 int end[510]; 20 int root,L; 21 int newnode() 22 { 23 for(int i = 0;i < 4;i++) 24 next[L][i] = -1; 25 end[L++] = 0; 26 return L-1; 27 } 28 void init() 29 { 30 L = 0; 31 root = newnode(); 32 } 33 int getch(char ch) 34 { 35 if(ch == 'A')return 0; 36 else if(ch == 'C')return 1; 37 else if(ch == 'G')return 2; 38 else return 3; 39 } 40 void insert(char buf[]) 41 { 42 int len = strlen(buf); 43 int now = root; 44 for(int i = 0;i < len;i++) 45 { 46 if(next[now][getch(buf[i])] == -1) 47 next[now][getch(buf[i])] = newnode(); 48 now = next[now][getch(buf[i])]; 49 } 50 end[now] ++; 51 } 52 void build() 53 { 54 queue<int>Q; 55 fail[root] = root; 56 for(int i = 0;i < 4;i++) 57 if(next[root][i] == -1) 58 next[root][i] = root; 59 else 60 { 61 fail[next[root][i]] = root; 62 Q.push(next[root][i]); 63 } 64 while(!Q.empty()) 65 { 66 int now = Q.front(); 67 Q.pop(); 68 end[now] += end[fail[now]];/********/ 69 for(int i = 0;i < 4;i++) 70 if(next[now][i] == -1) 71 next[now][i] = next[fail[now]][i]; 72 else 73 { 74 fail[next[now][i]] = next[fail[now]][i]; 75 Q.push(next[now][i]); 76 } 77 } 78 } 79 int dp[510][11*11*11*11+5]; 80 int bit[4]; 81 int num[4]; 82 int solve(char buf[]) 83 { 84 int len = strlen(buf); 85 memset(num,0,sizeof(num)); 86 for(int i = 0;i < len;i++) 87 num[getch(buf[i])]++; 88 bit[0] = (num[1]+1)*(num[2]+1)*(num[3]+1); 89 bit[1] = (num[2]+1)*(num[3]+1); 90 bit[2] = (num[3]+1); 91 bit[3] = 1; 92 memset(dp,-1,sizeof(dp)); 93 dp[root][0] = 0; 94 for(int A = 0;A <= num[0];A++) 95 for(int B = 0;B <= num[1];B++) 96 for(int C = 0;C <= num[2];C++) 97 for(int D = 0;D <= num[3];D++) 98 { 99 int s = A*bit[0] + B*bit[1] + C*bit[2] + D*bit[3]; 100 for(int i = 0;i < L;i++) 101 if(dp[i][s] >= 0) 102 { 103 for(int k = 0;k < 4;k++) 104 { 105 if(k == 0 && A == num[0])continue; 106 if(k == 1 && B == num[1])continue; 107 if(k == 2 && C == num[2])continue; 108 if(k == 3 && D == num[3])continue; 109 dp[next[i][k]][s+bit[k]] = max(dp[next[i][k]][s+bit[k]],dp[i][s]+end[next[i][k]]); 110 } 111 } 112 } 113 int ans = 0; 114 int status = num[0]*bit[0] + num[1]*bit[1] + num[2]*bit[2] + num[3]*bit[3]; 115 for(int i = 0;i < L;i++) 116 ans = max(ans,dp[i][status]); 117 return ans; 118 } 119 }; 120 char buf[50]; 121 Trie ac; 122 int main() 123 { 124 // freopen("in.txt","r",stdin); 125 // freopen("out.txt","w",stdout); 126 int n; 127 int iCase = 0; 128 while( scanf("%d",&n) == 1 && n) 129 { 130 iCase++; 131 ac.init(); 132 for(int i = 0;i < n;i++) 133 { 134 scanf("%s",buf); 135 ac.insert(buf); 136 } 137 ac.build(); 138 scanf("%s",buf); 139 printf("Case %d: %d\n",iCase,ac.solve(buf)); 140 } 141 return 0; 142 }
View Code
13、HDU 3247 Resource Archiver
使用最短路预处理出状态的转移。这样可以优化很多
1 //============================================================================ 2 // Name : HDU.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <stdio.h> 11 #include <string.h> 12 #include <algorithm> 13 #include <queue> 14 using namespace std; 15 16 const int INF = 0x3f3f3f3f; 17 18 struct Trie 19 { 20 int next[60010][2],fail[60010],end[60010]; 21 int root,L; 22 int newnode() 23 { 24 for(int i = 0;i < 2;i++) 25 next[L][i] = -1; 26 end[L++] = 0; 27 return L-1; 28 } 29 void init() 30 { 31 L = 0; 32 root = newnode(); 33 } 34 void insert(char buf[],int id) 35 { 36 int len = strlen(buf); 37 int now = root; 38 for(int i = 0;i < len ;i++) 39 { 40 if(next[now][buf[i]-'0'] == -1) 41 next[now][buf[i]-'0'] = newnode(); 42 now = next[now][buf[i]-'0']; 43 } 44 end[now] = id; 45 } 46 void build() 47 { 48 queue<int>Q; 49 fail[root] = root; 50 for(int i = 0;i < 2;i++) 51 if(next[root][i] == -1) 52 next[root][i] = root; 53 else 54 { 55 fail[next[root][i]] = root; 56 Q.push(next[root][i]); 57 } 58 while( !Q.empty() ) 59 { 60 int now = Q.front(); 61 Q.pop(); 62 if(end[fail[now]] == -1)end[now] = -1; 63 else end[now] |= end[fail[now]]; 64 for(int i = 0;i < 2;i++) 65 if(next[now][i] == -1) 66 next[now][i] = next[fail[now]][i]; 67 else 68 { 69 fail[next[now][i]] = next[fail[now]][i]; 70 Q.push(next[now][i]); 71 } 72 } 73 } 74 int g[11][11]; 75 int dp[1025][11]; 76 int cnt; 77 int pos[11]; 78 int dis[60010]; 79 80 81 void bfs(int k) 82 { 83 queue<int>q; 84 memset(dis,-1,sizeof(dis)); 85 dis[pos[k]] = 0; 86 q.push(pos[k]); 87 while(!q.empty()) 88 { 89 int now = q.front(); 90 q.pop(); 91 for(int i = 0; i< 2;i++) 92 { 93 int tmp = next[now][i]; 94 if(dis[tmp]<0 && end[tmp] >= 0) 95 { 96 dis[tmp] = dis[now] + 1; 97 q.push(tmp); 98 } 99 } 100 } 101 for(int i = 0;i < cnt;i++) 102 g[k][i] = dis[pos[i]]; 103 } 104 105 106 int solve(int n) 107 { 108 109 pos[0] = 0; 110 cnt = 1; 111 for(int i = 0;i < L;i++) 112 if(end[i] > 0) 113 pos[cnt++] = i; 114 for(int i = 0; i < cnt;i++) 115 bfs(i); 116 117 for(int i = 0;i < (1<<n);i++) 118 for(int j = 0;j < cnt;j++) 119 dp[i][j] = INF; 120 dp[0][0] = 0; 121 for(int i = 0;i <(1<<n);i++) 122 for(int j = 0;j < cnt;j++) 123 if(dp[i][j]<INF) 124 { 125 for(int k = 0;k < cnt;k++) 126 { 127 if(g[j][k] < 0)continue; 128 if( j == k)continue; 129 dp[i|end[pos[k]]][k] = min(dp[i|end[pos[k]]][k],dp[i][j]+g[j][k]); 130 } 131 } 132 int ans = INF; 133 for(int j = 0;j < cnt;j++) 134 ans = min(ans,dp[(1<<n)-1][j]); 135 return ans; 136 } 137 }; 138 Trie ac; 139 char buf[1010]; 140 141 int main() 142 { 143 // freopen("in.txt","r",stdin); 144 // freopen("out.txt","w",stdout); 145 int n,m; 146 while(scanf("%d%d",&n,&m) == 2) 147 { 148 if(n == 0 && m == 0)break; 149 ac.init(); 150 for(int i = 0;i < n;i++) 151 { 152 scanf("%s",buf); 153 ac.insert(buf,1<<i); 154 } 155 for(int i = 0;i < m;i++) 156 { 157 scanf("%s",buf); 158 ac.insert(buf,-1); 159 } 160 ac.build(); 161 printf("%d\n",ac.solve(n)); 162 } 163 return 0; 164 }
View Code
14、ZOJ 3494 BCD Code
这道题很神,数位DP和AC自动机结合,太强大了。
题解here
1 //============================================================================ 2 // Name : ZOJ.cpp 3 // Author : 4 // Version : 5 // Copyright : Your copyright notice 6 // Description : Hello World in C++, Ansi-style 7 //============================================================================ 8 9 #include <iostream> 10 #include <stdio.h> 11 #include <string.h> 12 #include <algorithm> 13 #include <queue> 14 using namespace std; 15 16 struct Trie 17 { 18 int next[2010][2],fail[2010]; 19 bool end[2010]; 20 int root,L; 21 int newnode() 22 { 23 for(int i = 0;i < 2;i++) 24 next[L][i] = -1; 25 end[L++] = false; 26 return L-1; 27 } 28 void init() 29 { 30 L = 0; 31 root = newnode(); 32 } 33 void insert(char buf[]) 34 { 35 int len = strlen(buf); 36 int now = root; 37 for(int i = 0;i < len ;i++) 38 { 39 if(next[now][buf[i]-'0'] == -1) 40 next[now][buf[i]-'0'] = newnode(); 41 now = next[now][buf[i]-'0']; 42 } 43 end[now] = true; 44 } 45 void build() 46 { 47 queue<int>Q; 48 fail[root] = root; 49 for(int i = 0;i < 2;i++) 50 if(next[root][i] == -1) 51 next[root][i] = root; 52 else 53 { 54 fail[next[root][i]] = root; 55 Q.push(next[root][i]); 56 } 57 while(!Q.empty()) 58 { 59 int now = Q.front(); 60 Q.pop(); 61 if(end[fail[now]])end[now] = true; 62 for(int i = 0;i < 2;i++) 63 if(next[now][i] == -1) 64 next[now][i] = next[fail[now]][i]; 65 else 66 { 67 fail[next[now][i]] = next[fail[now]][i]; 68 Q.push(next[now][i]); 69 } 70 } 71 } 72 }; 73 Trie ac; 74 75 int bcd[2010][10]; 76 int change(int pre,int num) 77 { 78 if(ac.end[pre])return -1; 79 int cur = pre; 80 for(int i = 3;i >= 0;i--) 81 { 82 if(ac.end[ac.next[cur][(num>>i)&1]])return -1; 83 cur = ac.next[cur][(num>>i)&1]; 84 } 85 return cur; 86 } 87 void pre_init() 88 { 89 for(int i = 0;i <ac.L;i++) 90 for(int j = 0;j <10;j++) 91 bcd[i][j] = change(i,j); 92 } 93 const int MOD = 1000000009; 94 long long dp[210][2010]; 95 int bit[210]; 96 97 long long dfs(int pos,int s,bool flag,bool z) 98 { 99 if(pos == -1)return 1; 100 if(!flag && dp[pos][s]!=-1)return dp[pos][s]; 101 long long ans = 0; 102 if(z) 103 { 104 ans += dfs(pos-1,s,flag && bit[pos]==0,true); 105 ans %= MOD; 106 } 107 else 108 { 109 if(bcd[s][0]!=-1)ans += dfs(pos-1,bcd[s][0],flag && bit[pos]==0,false); 110 ans %= MOD; 111 } 112 int end = flag?bit[pos]:9; 113 for(int i = 1;i<=end;i++) 114 { 115 if(bcd[s][i]!=-1) 116 { 117 ans += dfs(pos-1,bcd[s][i],flag&&i==end,false); 118 ans %=MOD; 119 } 120 } 121 if(!flag && !z)dp[pos][s] = ans; 122 return ans; 123 } 124 125 long long calc(char s[]) 126 { 127 int len = strlen(s); 128 for(int i = 0;i < len;i++) 129 bit[i] = s[len-1-i]-'0'; 130 return dfs(len-1,0,1,1); 131 } 132 char str[210]; 133 int main() 134 { 135 // freopen("in.txt","r",stdin); 136 // freopen("out.txt","w",stdout); 137 int T; 138 scanf("%d",&T); 139 int n; 140 while(T--) 141 { 142 ac.init(); 143 scanf("%d",&n); 144 for(int i = 0;i < n;i++) 145 { 146 scanf("%s",str); 147 ac.insert(str); 148 } 149 ac.build(); 150 pre_init(); 151 memset(dp,-1,sizeof(dp)); 152 int ans = 0; 153 scanf("%s",str); 154 int len = strlen(str); 155 for(int i = len -1;i >=0;i--) 156 { 157 if(str[i]>'0') 158 { 159 str[i]--; 160 break; 161 } 162 else str[i] = '9'; 163 } 164 ans -= calc(str); 165 ans %=MOD; 166 scanf("%s",str); 167 ans += calc(str); 168 ans %=MOD; 169 if(ans < 0)ans += MOD; 170 printf("%d\n",ans); 171 } 172 return 0; 173 }
View Code
转载于:https://www.cnblogs.com/13224ACMer/p/4873257.html
转自kuangbin的AC自动机(赛前最后一博)相关推荐
- 提高篇 第二部分 字符串算法 第4章 AC自动机
https://blog.csdn.net/wangyh1008/article/details/81428056 [模板]AC自动机(加强版) 洛谷3796 AC自动机_A_loud_name-CS ...
- 后缀自动机 AC自动机
trie树可遍历出所有无重复后缀,通过后缀遍历前缀可得到所有子串:后缀链接把所有后缀相同的状态(以当前节点为endpos的子串)连接起来,便有了类似KMP的next数组的性质. ...
- HDU2222 Keywords Search(AC自动机模板)
AC自动机是一种多模式匹配的算法.大概过程如下: 首先所有模式串构造一棵Trie树,Trie树上的每个非根结点都代表一个从根出发到该点路径的字符串. 然后每个结点都计算出其fail指针的值,这个fai ...
- hdu5384(AC自动机+纪录重复单词出现的次数)
题意: 给出n篇文章,m个单词,输出每篇文章中单词出现的次数,其中单词会重复. 思路: AC自动机模板题,添加一个单词的结尾标记记录即可.这里我们用了kuangbin的模板. 代码: #include ...
- AC自动机-HDU2222-模板题
http://acm.hdu.edu.cn/showproblem.php?pid=2222 一个AC自动机的模板题.用的kuangbin的模板,静态建Trie树.可能遇到MLE的情况要转动态建树. ...
- POJ - 1625 Censored!(AC自动机+dp+高精度运算)
题目链接:点击查看 题目大意:给出一个含有 n 个不同字符的字符集,接着规定所有单词的长度为 m ,再给出 k 个病毒串,问有多少个字符串中不含有病毒串 题目分析:这个题目和之前做过的DNA的那个题有 ...
- AC自动机及KMP练习
好久都没敲过KMP和AC自动机了.以前只会敲个kuangbin牌板子套题.现在重新写了自己的板子加深了印象.并且刷了一些题来增加自己的理解. KMP网上教程很多,但我的建议还是先看AC自动机(Trie ...
- Aho-Corasick 多模式匹配算法(AC自动机) 的算法详解及具体实现
多模式匹配 多模式匹配就是有多个模式串P1,P2,P3-,Pm,求出所有这些模式串在连续文本T1-.n中的所有可能出现的位置. 例如:求出模式集合{"nihao","ha ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
最新文章
- (推荐阅读)H264, H265硬件编解码基础及码流分析
- Sublime text3 新建 HTML文件
- 大杂烩 -- 四种生成和解析XML文档的方法详解
- 快手员工泄露10亿元公司机密 被开除并收回期权,官方暂未回应...
- bug经验-文件路径问题
- linux启动 mongo 不了问题
- (转)这是券商对金融科技最看重的一年!
- html远程连接mysql_mysql允许远程连接
- JavaFX之Scene Builder详细使用说明之设置篇(2)——属性Properties
- java fastjson 格式化_json的格式化展示(基于 fastjson)
- 给手机安装sqlite3
- php x63 157 162,浙江理工大学 我的编程之路 零基础学C/C++ 200题 标程/题解
- 从来不敷面膜的人_女人一旦过了40岁,敷面膜要记住“3不要”,否则还不如不敷!...
- SQLServer查询某天数据语法
- Ubuntu系统配置共享打印机及Windows连接教程
- 5G安全的全球统一认证体系和标准演进
- HTC ONE X刷ruu的详细刷机教程
- matplotlib给某一个点添加注释
- navicat导出和导入数据库里面的数据
- 21.网络互联与网络互联设备
热门文章
- 笔记本电脑电池使用方式/BIOS信息
- 计算机毕业设计java课程设计程序设计SSM框架网上书城全套含微信支付
- python的递归为什么难理解_为什么Python有最大的递归深度?
- 保姆级redis6全流程学习和redis秒杀全流程
- 量化交易 米筐 多因子策略总结
- Python 之父入职微软要搞事?!给大家推几本书压压惊
- docker-compose、kubernetes安装部署fastdfs文件集群系统
- VisualStdio调试出现0xC00000FD:Stack overflow原因及解决方法
- hive获取某日期是今年第几天
- iOS 调整UIPageControl圆点大小