bzoj2764 JLOI2011基因补全

Description

在生物课中我们学过,碱基组成了DNA(脱氧核糖核酸),他们分别可以用大写字母A,C,T,G表示,其中A总与T配对,C总与G配对。两个碱基序列能相互匹配,当且仅当它们等长,并且任意相同位置的碱基都是能相互配对的。例如ACGTC能且仅能与TGCAG配对。一个相对短的碱基序列能通过往该序列中任意位置补足碱基来与一个相对长的碱基序列配对。补全碱基的位置、数量不同,都将视为不同的补全方案。现在有两串碱基序列S和T,分别有n和m个碱基(n>=m),问一共有多少种补全方案。

Input

数据包括三行。
第一行有两个整数n,m,表示碱基序列的长度。
第二行包含n个字符,表示碱基序列S。
第三行包含m个字符,表示碱基序列T。
两个碱基序列的字符种类只有A,C,G,T这4个大写字母。

Output

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

Sample Input

10 3
CTAGTAGAAG
TCC

Sample Output

4

HINT

样例解释:
TCC的4种补全方案(括号中字符为补全的碱基)
(GA)TC(AT)C(TTC)
(GA)TC(ATCTT)C
(GA)T(CAT)C(TT)C
(GATCA)TC(TT)C

数据范围:
30%数据  n<=1000,m<=2
50%数据  n<=1000,m<=4
100%数据 n<=2000,m<=n

这是一道LCS方案数的题目,f[j]+=f[j-1](当a[i]==b[j]时)

注意要用高精度!!!

#include<stdio.h>
#include<string.h> 
char a[2001];
char b[2001],la,lb;
int mod=1e8;	
int f[2001][2001];
int cnt[2001];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	scanf("%s%s",a+1,b+1);
 	f[0][1]=1; 
 	cnt[0]=1;
    for(int i=0;i<=m;i++) 
		cnt[i]=1;
	for(int i=1;i<=n;i++)
	{
		if(a[i]=='A')
			a[i]='T';
		else if(a[i]=='C')
			a[i]='G';
		else if(a[i]=='T')
			a[i]='A';
		else
			a[i]='C';				
	}
	for(int i=1;i<=n;i++)
		for(int j=m;j>0;j--)
		{
			if(a[i]!=b[j])
				continue;
			if(cnt[j]<cnt[j-1])
				cnt[j]=cnt[j-1];
        	for(int l=1;l<=cnt[j];l++) 
			{
        		f[j][l]+=f[j-1][l];
        		if(f[j][l]>=mod) 
        		{
					f[j][l+1]+=f[j][l]/mod;
					f[j][l]%=mod;		        	
		        }
        	}
	        while(f[j][cnt[j]+1]) 
				cnt[j]++;			
		}
	printf("%d",f[m][cnt[m]]);
    for(int i=cnt[m]-1;i>0;i--) 
		printf("%08d",f[m][i]);				
}
f数组的第二维我用一个cnt来存的,为了求高精度.

剩下的就不难了.

猜你喜欢

转载自blog.csdn.net/zyq_20030305/article/details/79149798
今日推荐