BZOJ 2764 [JLOI2011]基因补全

题目: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;
}

你可能感兴趣的:(dp,高精度)