zoukankan      html  css  js  c++  java
  • hdu 4899 Hero meet devil

    传送阵:http://acm.hdu.edu.cn/showproblem.php?pid=4899

    题目大意:给定一个DNA序列,求有多少长度为m的序列与该序列的最长公共子序列长度为0,1...|S|;


    分析:
    我们可以考虑对于求两个串的最长公共子序列的dp:f[i,j]代表第一个串到了i,第二个串到了j的最长公共子序列。对于两个串来说,如果数组f[i]是完全一样的,则它们对后面的影响也是完全一样的,所以我们可以设2维状态:F[i,j]代表我们当前以及到了i,f[i]的状态为j的方案数,但是这样设状态第二维有10^10。我们发现一个f[i,j]一定不会比f[i,j-1]小,且最多比f[i,j-1]多1,所以我们在设状态的时候可以取个差值,就变成2^10了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define maxn 20
    #define mod 1000000007
    char dic[]="ACTG";
    int add[1<<15][4];
    int dp[2][1<<15];
    int pre[maxn],lcs[maxn],ans[maxn];
    char s[maxn];
    int T,n,m;
    void Add(int &x,int y){
        x+=y;
        if(x>=mod)x-=mod;
    }
    void init(){
        scanf("%s",s+1);n=strlen(s+1);
        memset(add,0,sizeof(add));
        memset(dp,0,sizeof(dp));
        for(int state=0;state<(1<<n);++state){
            pre[0]=0;
            for(int i=1;i<=n;++i)pre[i]=pre[i-1]+((state>>(i-1))&1);
            for(int k=0;k<4;++k){
                for(int i=1;i<=n;++i)
                    if(s[i]==dic[k])lcs[i]=pre[i-1]+1;
                    else lcs[i]=max(lcs[i-1],pre[i]);
                int &t=add[state][k];
                for(int i=1;i<=n;++i)
                    t|=((lcs[i]!=lcs[i-1])<<(i-1));
            }
        }
    }
    int get(int x){
        int s=0;
        while(x){
            s+=x&1;
            x>>=1;
        }return s;
    }
    void work(){
        scanf("%d",&m);
        int *now=dp[0],*next=dp[1];
        memset(next,0,(1<<n)*sizeof(int));
        next[0]=1;
        for(int i=1;i<=m;++i){
            swap(now,next);
            memset(next,0,(1<<n)*sizeof(int));
            for(int state=0;state<(1<<n);++state)
                if(now[state])
                    for(int k=0;k<4;++k)
                        Add(next[add[state][k]],now[state]);
        }
        memset(ans,0,sizeof(ans));
        for(int i=0;i<(1<<n);++i)
            Add(ans[get(i)],next[i]);
        for(int i=0;i<=n;++i)
            printf("%d
    ",ans[i]);
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            init();
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    大整数相加算法
    java中String和char的区别
    Git命令
    Dart随记
    用nodejs或者Chrome控制台的js对URI进行编码或解码
    Rust执行cmd或shell命令
    cargo expand用于查看被宏隐藏的代码
    Blocking waiting for file lock on package cache
    Rust生命周期之个人理解
    Rust为基础类型实现Trait
  • 原文地址:https://www.cnblogs.com/117208-/p/5352693.html
Copyright © 2011-2022 走看看