4606: [Apio2008]DNA
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 63 Solved: 36
[Submit][Status][Discuss]
Description
分析如DNA序列这样的生命科学数据是计算机的一个有趣应用。从生物学的角度上说,DNA 是一种由腺嘌呤、胞嘧啶
、鸟嘌呤和胸腺嘧啶这四种核苷酸组成的链式结构。这四种核苷酸分别用大写字母A、C、G、T表示。这样,一条DNA
单链可以被表示为一个只含以上四种字符的字符串。我们将这样的字符串称作一个DNA序列 。有时生物学家可能无
法确定一条DNA单链中的某些核苷酸。在这种情况下,字符N将被用来表示一个不确定的核苷酸。换句话说,N可以用
来表示A、C、G、T中的任何一个字符。我们称包含一个或者多个N的DNA序列为未完成序列;反之,就称作完成序列。
如果一个完成序列可以通过将一个未完成序列中的每个N任意替换成A、C、G、T得到的话,就称完成序列适合这个未
完成序列。举例来说,ACCCT适合ACNNT,但是AGGAT不适合。研究者们经常按照如下方式排序四种核苷酸:A优先于C,C
优先于G,G优先于T。如果一个DNA序列中的每个核苷酸都与其右边的相同或者优先,就将其归类为范式-1。举例来说
,AACCGT是范式-1,但是AACGTC不是。一般来说,一个DNA序列属于范式-j(j>1),只要它属于范式-(j-1)或者是一个范
式-(j-1)和一个范式-1的连接。举例来说,AACCC、ACACC和ACACA都是范式-3,但GCACAC和ACACACA不是。同样,研究
者们按照字典序对 DNA 序列进行排序。按照这个定义,最小的属于范式-3的DNA序列是AAAAA,最大的是TTTTT。这里
是另外一个例子,考虑未完成序列 ACANNCNNG。那么前7个适合这个未完成序列的DNA序列是:
ACAAACAAG
ACAAACACG
ACAAACAGG
ACAAACCAG
ACAAACCCG
ACAAACCGG
ACAAACCTG
写一个程序,找到按字典序的第R个适合给定的长度为M的未完成序列的范式-K。
Input
输入第一行包含三个由空格隔开的整数:M(1≤M≤50,000),K(1≤K≤10)和R(1≤R≤2×10^12)。
第二行包含一个长度为M的字符串,表示未完成序列。
保证适合该未完成序列的范式-K的总数不超过4×10^18
因此该数可以用C和C++中的long long类型或者Pascal中的Int64类型表示。
同时,R不会超过适合给定未完成序列的范式-K的总数。
Output
在第一行中输出第R个适合输入中的未完成序列的范式-K。
Sample Input
9 3 5
ACANNCNNG
ACANNCNNG
Sample Output
ACAAACCCG
HINT
Source
鸣谢Yts1999上传
题意:
给定一个长度为m的由ACGTN组成的字符串,定义大小关系A
M⩽50000 R⩽1012 K⩽10
题解:
明显的计数类DP
用f[i][j][k]表示第i到n位第i位是j,这部分分了k段的个数.
这个容易转移,然后我们就一步步走呗。
f[i][j][k]=∑(f[i+1,l,k或k-1]){k或k-1视j与l的关系而定,如果j>l则为k-1,否则为k}。
复杂度 O(16MK)
#includeusing namespace std; typedef long long ll; const int N=5e4+5; int n,m,a[N];ll now; ll f[N][5][11]; ll s[N][5][11]; char str[N],path[6]={0,'A','C','G','T'}; int main(){ scanf("%d%d%lld",&n,&m,&now);//M K R scanf("%s",str+1); for(int i=1;i<=n;i++){ if(str[i]!='N'){ a[i]=str[i]=='A'?1: str[i]=='C'?2: str[i]=='G'?3:4; } } if(a[n]) f[n][a[n]][1]=1; else for(int i=1;i<=4;i++) f[n][i][1]=1; for(int i=n-1;i;i--){ for(int j=1;j<=4;j++){ if(!a[i]||a[i]==j){ for(int k=1;k<=m;k++){ for(int l=1;l<=4;l++){ f[i][j][k]+=f[i+1][l][k-(l<j)]; } } } } } for(int i=1;i<=n;i++){ for(int j=1;j<=4;j++){ for(int k=1;k<=m;k++){ s[i][j][k]=s[i][j][k-1]+f[i][j][k]; } } } for(int i=1,j,k=0;i<=n;i++){ if(a[i]){ putchar(path[a[i]]); if(k>a[i]) m--; k=a[i]; } else{ for(j=1;j<=4&&s[i][j][m-(k>j)] j)]; putchar(path[j]); if(k>j) m--; k=j; } } return 0; }