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
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
正解:DP+高精度
解题报告:
好久没写题了,感觉只要不是考试就写不动题了。。。
这道题其实挺水的,就是一个编辑距离。考虑f[i][j]表示长串匹配到i,短串匹配到j的方案数,显然对于长串而言,我们需要在短串的对应位置补一些新的数字才行。所以f[i][j]=f[i-1][j]表示i这一位上与之相对应的短串上填一个新的数字,并且如果a[i]与b[j]能匹配,那么f[i][j]+=f[i-1][j-1];表示各匹配一位。
因为答案很大,所以要写高精度。还要滚动数组。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 2011; 21 const int MOD = 100000000; 22 int n,m; 23 int match[5],a[MAXN],b[MAXN]; 24 //int f[MAXN][MAXN][10];//f[i][j]表示长串匹配到i,短串匹配到j的方案数,滚动数组 25 //int cnt[MAXN][MAXN]; 26 int cnt[MAXN]; 27 int f[MAXN][50]; 28 29 inline int getint() 30 { 31 int w=0,q=0; 32 char c=getchar(); 33 while((c<'0' || c>'9') && c!='-') c=getchar(); 34 if (c=='-') q=1, c=getchar(); 35 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 36 return q ? -w : w; 37 } 38 /* 39 inline void add(int x,int y,int i,int j){ 40 int now=1; 41 if(cnt[x][y]<cnt[i][j]) cnt[x][y]=cnt[i][j]; 42 while(now<=cnt[x][y]) { 43 f[x][y][now]+=f[i][j][now]; now++; 44 } 45 for(int i=1;i<=cnt[x][y];i++) 46 if(f[x][y][i]>=MOD) 47 f[x][y][i+1]+=f[x][y][i]/MOD,f[x][y][i]%=MOD; 48 while(f[x][y][cnt[x][y]+1]) cnt[x][y]++; 49 }*/ 50 51 inline void work(){ 52 n=getint(); m=getint(); char c; 53 match[1]=3; match[2]=4; match[3]=1; match[4]=2; 54 for(int i=1;i<=n;i++) { 55 c=getchar(); 56 while(c<'A' || c>'T') c=getchar(); 57 if(c=='A') a[i]=1; else if(c=='C') a[i]=2; else if(c=='T') a[i]=3; else a[i]=4; 58 } 59 for(int i=1;i<=m;i++) { 60 c=getchar(); 61 while(c<'A' || c>'T') c=getchar(); 62 if(c=='A') b[i]=1; else if(c=='C') b[i]=2; else if(c=='T') b[i]=3; else b[i]=4; 63 } 64 65 f[0][1]=1; cnt[0]=1; 66 for(int i=0;i<=m;i++) cnt[i]=1; 67 for(int i=1;i<=n;i++) 68 for(int j=m;j>=1;j--) { 69 if(match[a[i]]!=b[j]) continue; 70 if(cnt[j]<cnt[j-1]) cnt[j]=cnt[j-1]; 71 for(int l=1;l<=cnt[j];l++) { 72 f[j][l]+=f[j-1][l]; 73 if(f[j][l]>=MOD) f[j][l+1]+=f[j][l]/MOD,f[j][l]%=MOD; 74 } 75 while(f[j][cnt[j]+1]) cnt[j]++; 76 } 77 printf("%d",f[m][cnt[m]]); 78 for(int i=cnt[m]-1;i>=1;i--) printf("%08d",f[m][i]); 79 /* 80 for(int i=0;i<=n;i++) for(int j=0;j<=m;j++) cnt[i][j]=1; 81 for(int i=0;i<=n;i++) f[i][0][1]=1; 82 for(int i=1;i<=n;i++) 83 for(int j=m;j>=1;j--) { 84 if(cnt[i][j]<cnt[i-1][j])cnt[i][j]=cnt[i-1][j]; 85 for(int l=1;l<=cnt[i-1][j];l++) f[i][j][l]=f[i-1][j][l]; //一位新添加一个数 86 if(match[a[i]]==b[j]){ 87 add(i,j,i-1,j-1);//由上一位转移过来 88 } 89 } 90 printf("%d",f[n][m][cnt[n][m]]); 91 for(int i=cnt[n][m]-1;i>=1;i--) printf("%08d",f[n][m][i]);*/ 92 } 93 94 int main() 95 { 96 work(); 97 return 0; 98 }