bzoj1030解题报告 tag:AC自动机+DP
很开心在CNBLOG开通了博客,发布第一篇解题报告。借此机会,我也希望和广大的大神们交流学习。
题意是给出N个可识别字符串和一个长度M。求在26M的这么多种字符串的可能性中找出有多少种字符串包含这N个字符串中的一个或多个,并把最终答案对10007取模。
思路很容易想到是AC自动机+DP。
f[d][i][j] (d=0..1, i=0..M, j=0..自动机状态数) 表示d表示当前状态取过没有,匹配到第i位,匹配到自动机的j状态所能得到的字符串数。
动态转移方程:f[d|next[j]][i+1][next[j]] += f[d][i][j]
最后统计∑f[1][M][i]。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 5 #define N 8000 6 #define Module 10007 7 8 using namespace std; 9 10 struct node{ 11 int terminal, num; 12 node* next[26]; 13 node* fail; 14 node() { fail=NULL; terminal=0; memset(next,0,sizeof(next)); } 15 } *root, *q[N]; 16 char st[N]; 17 int n, m, head, tail, f[2][103][N]; 18 19 void insert() 20 { 21 node* p=root; 22 for (int i=0; st[i]; i++) 23 { 24 int index = st[i]-'A'; 25 if (p->next[index]==NULL) p->next[index] = new node(); 26 p = p->next[index]; 27 } 28 p->terminal = 1; 29 } 30 31 void ac_auto() 32 { 33 head=-1, tail=0; q[0]=root; 34 while (head<tail) 35 { 36 node *p = q[++head], *tmp; 37 p->num = head; 38 for (int i=0;i<26;i++) 39 if (p->next[i]!=NULL) 40 { 41 if (p==root) p->next[i]->fail = root; 42 else 43 { 44 tmp = p->fail; 45 while (tmp!=NULL) 46 { 47 if (tmp->next[i]!=NULL) 48 { 49 p->next[i]->fail = tmp->next[i]; 50 break; 51 } 52 tmp = tmp->fail; 53 } 54 if (tmp==NULL) p->next[i]->fail = root; 55 } 56 if (p->next[i]->fail!=NULL && p->next[i]->fail->terminal) p->next[i]->terminal = 1; 57 q[++tail] = p->next[i]; 58 } 59 } 60 } 61 62 void dp() 63 { 64 memset(f, 0, sizeof(f)); 65 f[0][0][0] = 1; 66 for (int d=0;d<2;d++) 67 for (int i=0;i<m;i++) 68 for (int j=0;j<=head;j++) 69 if (f[d][i][j]) 70 for (int k=0;k<26;k++) 71 { 72 node* p = q[j]; 73 while (p && p->next[k]==NULL) p=p->fail; 74 if (p==NULL) p=root; 75 if (p->next[k]) p=p->next[k]; 76 (f[d|p->terminal][i+1][p->num] += f[d][i][j]) %= Module; 77 } 78 int ans = 0; 79 for (int i=0;i<=head;i++) 80 (ans += f[1][m][i]) %= Module; 81 printf("%d\n",ans); 82 } 83 84 int main() 85 { 86 #ifndef ONLINE_JUDGE 87 freopen("bzoj1030.in","r",stdin); 88 freopen("bzoj1030.out","w",stdout); 89 #endif 90 scanf("%d%d",&n,&m); 91 root = new node(); 92 while (n--) 93 { 94 scanf("%s",st); 95 insert(); 96 } 97 ac_auto(); 98 dp(); 99 return 0; 100 }
一开始AC自动机写错了,DEBUG了一个晚上,还好还是DEBUG出来了。
贴一组数据:
bzoj1030.in
8 3
A
BB
CCC
DDDD
ZZZZZZ
L
N
XDAFEW
bzoj1030.out
5455