基因补全

来源:互联网 发布:java时间戳转换成秒 编辑:程序博客网 时间:2024/06/05 07:35

题目描述

在生物课中我们学过,碱基组成了DNA(脱氧核糖核酸),他们分别可以用大写字母A,C,T,G表示,其中A总与T配对,C总与G配对。两个碱基序列能相互匹配,当且仅当它们等长,并且任意相同位置的碱基都是能相互配对的。例如ACGTC能且仅能与TGCAG配对。一个相对短的碱基序列能通过往该序列中任意位置补足碱基来与一个相对长的碱基序列配对。补全碱基的位置、数量不同,都将视为不同的补全方案。现在有两串碱基序列S和T,分别有n和m个碱基(n>=m),问一共有多少种补全方案。

输入

数据包括三行。
第一行有两个整数n,m,表示碱基序列的长度。
第二行包含n个字符,表示碱基序列S。
第三行包含m个字符,表示碱基序列T。 两个碱基序列的字符种类只有A,C,G,T这4个大写字母。

输出

答案只包含一行,表示补全方案的个数。
样例输入 10 3

CTAGTAGAAG

TCC 样例输出 4 提示
TCC的4种补全方案(括号中字符为补全的碱基)
(GA)TC(AT)C(TTC)
(GA)TC(ATCTT)C
(GA)T(CAT)C(TT)C
(GATCA)TC(TT)C

题目分析:
关键字:DP
虽然题目一大堆,但核心就是让你求B串在A串的排列组合方案数,因为只要你将B串中的每个字符在A串中一一对应,那么肯定拥有一种方案(因为其它是随便填的,补全即可)。
这种题目往往都是用DP写的,但也不排除排列组合的可能,显然这题是DP
给出DP三要素:
定义:dp[i]表示扫描到目前A串达到B串前i个的排列组合有多少种方案
初始化:dp[0]=1;
状态转移方程:if(s[i]==t[j]) dp[j]+=dp[j-1];
最后输出dp[m]即可,记得加高精度。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define M 100000000#define LL long long#define N 2005int n,m;LL ans;char s[N],t[N];//s表示A串,t表示B串struct bignum{//高精度    int num[105],n;    bignum(){        n=1;        memset(num,0,sizeof(num));    }    bignum operator + (bignum x){        bignum tmp;        int m=max(n,x.n);        for(int i=1;i<=m;i++){            tmp.num[i]+=num[i]+x.num[i];            if(tmp.num[i]>=M) {                tmp.num[i]-=M;                tmp.num[i+1]++;            }        }        tmp.n=m;        if(tmp.num[m+1]>0)tmp.n++;        return tmp;    }    void Print(){        printf("%d",num[n]);        for(int i=n-1; i>=1; i--)printf("%08d",num[i]);    }}dp[N];int main(){    scanf("%d %d",&n,&m);    scanf("%s %s",s,t);    for(int i=0;i<m;i++){//将t改成对应的字符        if(t[i]=='A') t[i]='T';        else if(t[i]=='T') t[i]='A';        else if(t[i]=='C') t[i]='G';        else if(t[i]=='G') t[i]='C';    }    dp[0].num[1]=1;    for(int i=0; i<n; i++) for(int j=m; j>=1; j--)        //此处要反着循环,不然会重复更新        if(s[i]==t[j-1]) dp[j]=dp[j]+dp[j-1];    dp[m].Print();    return 0;}