基因的庇护 (AC自动机 dp)

来源:互联网 发布:淘宝衣服换号 编辑:程序博客网 时间:2024/05/16 08:21

基因的庇护

10.25

思路:
一道比较典型的AC自动机上DP,只不过需要分析一下性质。
由于每个位置都需要被庇护序列覆盖到,用dp[i][j][k]表示链长为i,在AC自动机上的j号点,当前链上倒数第k个位置是最左的没有被覆盖到的位置时的方案数。预处理出AC自动机上每个结点表示的串的最长的有庇护效应的后缀长度,转移时就看这个长度是否大于等于k+1,若大于等于则说明倒数第k个位置能被覆盖到了,即转移到dp[i+1][j'][0];否则转移到dp[i+1][j'][k+1]。
把dp[n][j][0]求和即为答案。
做不完的题,想不到的dp。。。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define N 105#define MOD 1000000009using namespace std;int n, m, tot;int head, tail;char s[20];int to[N][4], fail[N], cover[N];int dp[1005][N][12], q[N];inline void add(int &a, const int &b){    a += b;    if(a >= MOD) a -= MOD;}int re(char x){    if(x == 'A') return 0;    if(x == 'T') return 1;    if(x == 'C') return 2;    if(x == 'G') return 3;}void insert(){    int p = 0;    int len = strlen(s+1);    for(int i=1; i<=len; ++i){        if( !to[p][re(s[i])] ) to[p][re(s[i])] = ++tot;        p = to[p][re(s[i])];    }    cover[p] = len;}void get_fail(){    for(int i=0; i<4; ++i) if( to[0][i] ) q[tail++] = to[0][i];    while(head < tail){        int a = q[head++];        for(int i=0; i<4; ++i){            if( to[a][i] ){                fail[to[a][i]] = to[fail[a]][i];                q[tail++] = to[a][i];                cover[to[a][i]] = max(cover[to[a][i]], cover[fail[to[a][i]]]);            }            else to[a][i] = to[fail[a]][i];        }    }}void solve(){    dp[0][0][0] = 1;    for(int i=0; i<n; ++i){        for(int j=0; j<=tot; ++j){            for(int k=0; k<10; ++k){                if( !dp[i][j][k] ) continue;                for(int p=0; p<4; ++p){                    int v = to[j][p];                    if(cover[v] >= k+1) add(dp[i+1][v][0], dp[i][j][k]);                    else add(dp[i+1][v][k+1], dp[i][j][k]);                }            }        }    }    int ans = 0;    for(int i=0; i<=tot; ++i) add(ans, dp[n][i][0]);    printf("%d\n", ans);}int main(){    freopen("protect.in", "r", stdin);    freopen("protect.out", "w", stdout);    scanf("%d%d", &n, &m) ;    for(int i=1; i<=m; ++i){        scanf("%s", s+1) ;        insert();    }    get_fail();    solve();    return 0;}
原创粉丝点击