【dp,AC自动机】cf86C. Genetic engineering

http://codeforces.com/problemset/problem/86/C

     自动机好题,给你m个DNA片段,询问有多少个长度为n的DNA,被这m个片段中的若干个可重复的完全覆盖。

     太久没写关于AC自动机的题目,有点生疏想了一会才知道怎么做=。=~,对于AC自动机,有这样一个特性,停留在深度较大的节点时候可以继续拥有当前串所有更短后缀的信息,因为可以沿着fail指针寻找其后缀,故我们dp的时候需要贪心地尽量停留在高深度的节点。但是同时会丢失一部分信息,如果当前串前面一部分已经匹配成功,但是由于我们的贪心选择,我们没记录这个信息,因此额外添加dp的一维,当前串还有几位没被成功覆盖。如果dp时候沿着fail指针跳到比深度比没被覆盖位数小的结点,则可以认为我们跳过某些字符没有覆盖,该转移不合法。。。大致就是通过这个贪心以及多一维的信息记录来dp,详见代码:

View Code
  1 //By Lin
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #define MOD 1000000009
  6 using namespace std;
  7 
  8 const    char str[5] = "ACGT";
  9 inline    int id( char ch ){
 10     for (int i = 0; str[i]; i++)
 11         if ( ch == str[i] ) return i; 
 12 }
 13 int        ncnt;
 14 struct    Node{
 15     bool flag;
 16     int     num,depth;
 17     Node *next[4],*fail;
 18     Node(){
 19         flag = false; 
 20         depth = 0; 
 21         num = ncnt++;
 22         memset( next , false , sizeof(next) );
 23     }
 24 }*root;
 25 void    insert( char s[] ){
 26     Node *tmp = root;
 27     for (int i = 0; s[i]; i++ ) {
 28         int k = id(s[i]);
 29         if ( !tmp->next[k] ) {
 30             tmp->next[k] = new Node();
 31             tmp->next[k]->depth= tmp->depth+1;
 32         }
 33         tmp = tmp->next[k];
 34     }
 35     tmp->flag = true;
 36 }
 37 void    build_ac(){
 38     queue<Node*> que;
 39     for (int i = 0; i<4; i++ )
 40         if ( root->next[i] ) root->next[i]->fail = root, que.push( root->next[i] );
 41     while ( !que.empty() ) {
 42         Node *tmp = que.front(); que.pop();
 43         for (int i = 0; i<4; i++) if ( tmp->next[i] ){
 44             Node *p = tmp->fail; 
 45             while ( p!=root && !p->next[i] ) p = p->fail;
 46             if ( p->next[i] ) tmp->next[i]->fail = p->next[i];
 47             else tmp->next[i]->fail = root;
 48             que.push( tmp->next[i] );
 49         }
 50     }
 51 }
 52 
 53 int        n,m;
 54 char     s[15][15];
 55 int        dp[2][105][11];
 56 #define X first
 57 #define Y second
 58 queue<pair<Node*,int> > que[2];
 59 int        in_que[105][11];
 60 
 61 int        main(){
 62     scanf("%d%d",&n, &m );
 63     root = new Node();
 64     for (int i = 0; i<m; i++ ) {
 65         scanf("%s", s[i] );
 66         insert( s[i] );
 67     }
 68     build_ac();
 69     dp[0][0][0] = 1;
 70     que[0].push( make_pair(root,0) );
 71     int g = 0 , h = 1;
 72     for (int o = 0; o<n; o++){
 73         while ( !que[g].empty() ) {
 74             Node* tmp = que[g].front().X; 
 75             int      k = que[g].front().Y;
 76             que[g].pop();
 77             for (int i = 0; i<4; i++){
 78                 Node* p = tmp;
 79                 while ( p->depth>k && !p->next[i] ) p = p->fail;
 80                 if ( !p->next[i] || p->depth<k ) continue;
 81                 p = p->next[i];
 82                 int t = (k+1);
 83                 Node* pp = p; 
 84                 while ( pp->depth>t && !pp->flag ) pp = pp->fail;
 85                 if ( pp->depth>=k+1 && pp->flag ) t = 0; 
 86                 if ( in_que[p->num][t] != o+1 ) {
 87                     que[h].push( make_pair(p,t) );
 88                     in_que[p->num][t] = o+1;
 89                 }
 90                 dp[h][p->num][t] += dp[g][tmp->num][k];
 91                 dp[h][p->num][t] %= MOD;
 92             }
 93             dp[g][tmp->num][k] = 0; 
 94         }
 95         swap(g,h);
 96     }
 97     int ans = 0; 
 98     for (int i = 0; i<ncnt; i++) 
 99         ans = (ans+dp[g][i][0])%MOD;
100     printf("%d\n" , ans );
101     return 0;
102 }

 

posted @ 2012-12-04 16:16  lzqxh  阅读(280)  评论(0编辑  收藏  举报