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

 

posted @ 2014-05-15 14:48  Africamonkey  阅读(332)  评论(0编辑  收藏  举报