BZOJ 3864 Hero meet devil DP套DP

来源:互联网 发布:windows最好的系统 编辑:程序博客网 时间:2024/05/17 06:22

题目大意:给定一个长度为n(n15)的基因序列S,求对于每个i(0in)有多少长度为m(m1000)的基因串T满足STLCSi

考虑LCS怎么求
fi,j表示T的前i位和S的前j位的LCS
我们发现每一行之和上一行的状态有关

那么在这个问题中,我们令fi,j表示T的前i位与SLCS状态的第i行为j的状态数
由于每一行相邻两数最多差1,因此状态数不会超过2n,用一个二进制数存储相邻两项的差值即可
预处理所有转移后直接DP,时间复杂度O(4n2n+4m2n)

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MOD 1000000007using namespace std;const char letters[]={'A','C','G','T'};int n,m;char s[20];int trans[1<<15][4],cnt[1<<15],f[2][1<<15];void Pretreatment(){    int i,j,k;    for(i=0;i<1<<n;i++)    {        static int f[20],g[20];        for(j=1;j<=n;j++)            f[j]=f[j-1]+(i&(1<<j-1)?1:0);        cnt[i]=f[n];        for(k=0;k<4;k++)        {            for(j=1;j<=n;j++)            {                g[j]=max(g[j-1],f[j]);                if(letters[k]==s[j])                    g[j]=max(g[j],f[j-1]+1);            }            trans[i][k]=0;            for(j=1;j<=n;j++)                if(g[j]-g[j-1])                    trans[i][k]|=1<<j-1;        }    }}int main(){    int T,i,j,k;    for(cin>>T;T;T--)    {        scanf("%s%d",s+1,&m);        n=strlen(s+1);        Pretreatment();        memset(f,0,sizeof f);        f[0][0]=1;        for(i=1;i<=m;i++)        {            memset(f[i&1],0,sizeof(f[0][0])<<15);            for(j=0;j<1<<n;j++)                for(k=0;k<4;k++)                    (f[i&1][trans[j][k]]+=f[~i&1][j])%=MOD;        }        static int ans[20];        memset(ans,0,sizeof ans);        for(i=0;i<1<<n;i++)            (ans[cnt[i]]+=f[m&1][i])%=MOD;        for(i=0;i<=n;i++)            printf("%d\n",ans[i]);    }    return 0;}
3 1
原创粉丝点击