【JZOJ 3747】Problem C

Description

基因串是由ACGT4个字母组成的,我们有一个长度为n的基因串S。想要知道长度为m的基因串中,与S的最长公共子序列分别为0; 1; ; n的串各有几个。

输出答案关于10^9 + 7的余数。

n<=10;m<=1000

Solution

先看一下暴力,
每次枚举出一个大串b以后,用DP来算:
fi,j 表示大串做到位置i,小串匹配到j的最大匹配,
转移:

fi,j=max(fi1,j,fi,j1,fi1,j1+[aj=bi])

仔细观察,发现对于相同的i,如对于每一个j, fi,j 都相同,那么这两个 fi 对后面的影响都是一样的,哪怕b不一样;
还有性质,对于固定的i, fi,j 是不下降的,且上升最多+1,所以可以把它差分以后压成一个01串;
Fi,S 表示b串枚举到i位,S为压缩的 fi,j 的状态,值表示方案数,
每次转移枚举这位选什么,可以计算出当前位选了这个数后的新的S,然后更新;

细节蛮多的,读者自己想一下吧

复杂度: O(m2n4)

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
const int N=1005,M=12,mo=1e9+7;
int m,n;
int a[N],g[M];
LL f[N][2125];
LL ans[N];
int er[M+1];
int f1[2050][4],f2[2050];
int main()
{
    int q,w;
    er[1]=1;fo(i,2,12)er[i]=er[i-1]<<1;
    char ch=' ';
    for(;ch!='A'&&ch!='C'&&ch!='G'&&ch!='T';ch=getchar());
    for(;ch=='A'||ch=='C'||ch=='G'||ch=='T';ch=getchar())
    {
        if(ch=='A')a[++n]=1;
        if(ch=='C')a[++n]=2;
        if(ch=='G')a[++n]=3;
        if(ch=='T')a[++n]=4;
    }
    fo(i,0,er[n+1]-1)
        fo(j,1,4)
        {
            fo(k,1,n)g[k]=g[k-1]+((er[k]&i)?1:0);
            f2[i]=g[n];
            q=0;
            fod(k,n,1)g[k]=max(g[k],g[k-1]+(j==a[k]));
            fo(k,1,n)g[k]=max(g[k],g[k-1]);
            q=0;
            fo(k,1,n)if(g[k]!=g[k-1])q+=er[k];
            f1[i][j]=q;
        }
    scanf("%d",&m);
    f[0][0]=1;
    fo(I,0,m-1)
        fo(i,0,er[n+1]-1)if(f[I][i])
        {
            fo(j,1,4)
            {
                q=f1[i][j];
                f[I+1][q]=(f[I+1][q]+f[I][i])%mo;
            }
        }
    fo(i,0,er[n+1]-1)ans[f2[i]]=(ans[f2[i]]+f[m][i])%mo;
    fo(i,0,n)printf("%lld\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值