列表

详情


NC20129. [JLOI2011]基因补全

描述

在生物课中我们学过,碱基组成了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个大写字母。

输出描述

答案只包含一行,表示补全方案的个数。

示例1

输入:

10 3
CTAGTAGAAG
TCC

输出:

4

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++ 11.0.1) 解法, 执行用时: 513ms, 内存消耗: 17984K, 提交时间: 2022-08-14 10:19:03

#include<bits/stdc++.h>
using namespace std;
const int N=3e3;
const int M=1e8;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
int n,m;
char s[N+5],t[N+5];
struct BigInt{
	int x[N+5];
}dp[N+5];
BigInt operator +(const BigInt& a, const BigInt& b){
	BigInt tmp;
	memset(tmp.x,0,sizeof(tmp.x));
	tmp.x[0]=max(a.x[0],b.x[0]);
	for(int i=1;i<=tmp.x[0];i++){
		tmp.x[i]+=a.x[i]+b.x[i];
		if(tmp.x[i]>=M)tmp.x[i]-=M,tmp.x[i+1]++;
	}
	if(tmp.x[tmp.x[0]+1])tmp.x[0]++;
	return tmp;
}
int main(){
    ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m>>(s+1)>>(t+1);
	for(int i=1;i<=m;i++)
		if(t[i]=='A')t[i]='T';
		else if(t[i]=='T')t[i]='A';
		else if(t[i]=='C')t[i]='G';
		else t[i]='C';
	for(int i=0;i<=m;i++){
		memset(dp[i].x,0,sizeof(dp[i].x));
		dp[i].x[0]=1;
	}
	dp[0].x[1]=1;
	for(int i=1;i<=n;i++)
		for(int j=m;j;j--)
			if(s[i]==t[j])
				dp[j]=(dp[j]+dp[j-1]);
	cout<<dp[m].x[dp[m].x[0]];
	for(int i=dp[m].x[0]-1;i;i--)
		cout<<setw(8)<<setfill('0')<<dp[m].x[i];
	return 0;
}

上一题