BZOJ 2764 [JLOI2011]基因补全

来源:互联网 发布:永诚网络 编辑:程序博客网 时间:2024/06/05 12:46

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2764

题意:给定一个长度为n的碱基序列S和一个长度为m的碱基序列T,现在希望向序列T里补一定的碱基使得序列S和序列T配对,配对的规则是AT配对,CG配对,添加碱基的位置与数量不同的方案视为不同,求不同的方案数。0<mn2000

题解:
可以考虑算出序列T在序列S里匹配的本质不同方案数,利用dp可以很容易解决这个问题。
f[i][j]表示序列S前i位匹配序列T至第j位的方案数,则对于f[i][j],若不用S[i]匹配T[j],则为f[i1][j],若能匹配,则可由f[i1][j1]转化至该状态,最终的答案为f[n][m],dp可滚动。
粗略估计答案的上界,可以发现存在情况使得答案超过264,但不可能超过C(2000,1000)或者更小,dp直接配上高精度即可。

代码:

#include <cstdio>const int maxn = 2001, maxl = 70, mod = 1000000000;struct BigInt{    int len, num[maxl];    void getint(const int &x) { num[len++] = x; }    void Print()    {        printf("%d", num[len - 1]);        for(int i = len - 2; i >= 0; --i)            printf("%9.9d", num[i]);        putchar('\n');    }    void operator += (const BigInt &x)    {        if(len < x.len) len = x.len;        for(int i = 0; i < len; ++i)        {            num[i] += x.num[i];            if(num[i] >= mod)            {                num[i] -= mod;                ++num[i + 1];            }        }        if(num[len]) ++len;    }} f[maxn];inline bool check(char a, char b){    return a == 'A' && b == 'T' || a == 'G' && b == 'C' || a == 'C' && b == 'G' || a == 'T' && b == 'A';}int n, m;char s[maxn], t[maxn];int main(){    scanf("%d%d%s%s", &n, &m, s, t);    f[0].getint(1);    for(int i = 1; i <= n; ++i)        for(int j = m; j; --j)            if(check(s[i - 1], t[j - 1])) f[j] += f[j - 1];    f[m].Print();    return 0;}
0 0