【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 }

 

转载于:https://www.cnblogs.com/lzqxh/archive/2012/12/04/2801562.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值