您的位置:首页 > 其它

BZOJ 2764 [JLOI2011]基因补全

2015-02-26 20:25 176 查看
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2764

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

题解:

可以考虑算出序列T在序列S里匹配的本质不同方案数,利用dp可以很容易解决这个问题。

令f[i][j]f[i][j]表示序列S前i位匹配序列T至第j位的方案数,则对于f[i][j]f[i][j],若不用S[i]S[i]匹配T[j]T[j],则为f[i−1][j]f[i-1][j],若能匹配,则可由f[i−1][j−1]f[i-1][j-1]转化至该状态,最终的答案为f[n][m]f
[m],dp可滚动。

粗略估计答案的上界,可以发现存在情况使得答案超过2642^{64},但不可能超过C(2000,1000)C(2000,1000)或者更小,dp直接配上高精度即可。

代码:

[code]#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: