题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2764
题意:给定一个长度为n的碱基序列S和一个长度为m的碱基序列T,现在希望向序列T里补一定的碱基使得序列S和序列T配对,配对的规则是A
与T
配对,C
与G
配对,添加碱基的位置与数量不同的方案视为不同,求不同的方案数。0<m≤n≤2000。
题解:
可以考虑算出序列T在序列S里匹配的本质不同方案数,利用dp可以很容易解决这个问题。
令f[i][j]表示序列S前i位匹配序列T至第j位的方案数,则对于f[i][j],若不用S[i]匹配T[j],则为f[i?1][j],若能匹配,则可由f[i?1][j?1]转化至该状态,最终的答案为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;
}
时间: 2024-10-16 13:38:42