【BZOJ3864】Hero meet devil
Description
There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.
After the ring has been destroyed, the devil doesn‘t feel angry, and she is attracted by z*p‘s wisdom and handsomeness. So she wants to find z*p out.
But what she only knows is one part of z*p‘s DNA sequence S leaving on the broken ring.
Let us denote one man‘s DNA sequence as a string consist of letters from ACGT. The similarity of two string S and T is the maximum common subsequence of them, denote by LCS(S,T).
After some days, the devil finds that. The kingdom‘s people‘s DNA sequence is pairwise different, and each is of length m. And there are 4^m people in the kingdom.
Then the devil wants to know, for each 0 <= i <= |S|, how many people in this kingdom having DNA sequence T such that LCS(S,T) = i.
You only to tell her the result modulo 10^9+7.
Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains a string S. the second line contains an integer m.
T<=5
|S|<=15. m<= 1000.
Output
For each case, output the results for i=0,1,...,|S|, each on a single line.
Sample Input
1
GTC
10
Sample Output
1
22783
528340
497452
题意:给你一个串S,问所有长度为m的字符串中,与S串的最长公共子序列长度为1...|S|的串的个数。
题解:话说这种DP套DP的题最近有点流行~
还记得怎么求最长公共子序列吗?记得那个求最长公共子序列时的矩阵吗?不记得我就再说一遍。
令f[i][j]表示T串中到了第i个数,S串中到了第j个数,的LCS的长度。那么经典的DP方程:
$f[i][j]=max(f[i-1][j],f[i][j-1],(T[i]==S[j])?(f[i-1][j-1]+1):0)$
好了,但是我们求的是方案数,如果直接这样DP的话,需要记录的状态非常多(当前T可能的字符,之前T可能的字符。。。)。但是我们发现S的长度非常小,可以考虑把它单独拿出来处理一下。
因为每一行只能从上一行转移过来,我们不妨状压所有可能的行,暴力计算出在T中添加一个字符后会转移到哪个行。但是行中每一位的数不是0/1,差分一下就好了。处理出所有的转移后,再跑一个DP统计答案就行了。
#include <cstdio> #include <cstring> #include <iostream> #include <cstring> using namespace std; const int mod=1000000007; int n,m; int to[1<<16][4],s[20],cnt[1<<16],f[2][1<<16],ans[20]; char str[20]; void init() { memset(to,0,sizeof(to)); memset(cnt,0,sizeof(cnt)); memset(f,0,sizeof(f)); memset(ans,0,sizeof(ans)); int i,j,k,s1,s2,t1,t2,tar; for(i=0;i<(1<<n);i++) { if(i) cnt[i]=cnt[i-(i&-i)]+1; for(j=0;j<4;j++) { for(tar=s1=s2=t1=t2=0,k=0;k<n;k++) { t1=s1,t2=s2,s2+=((i>>k)&1),s1=max(t1,s2); if(s[k]==j) s1=max(s1,t2+1); tar|=((s1-t1)<<k); } to[i][j]=tar; } } } void work() { scanf("%s%d",str,&m),n=strlen(str); int i,j; for(i=0;i<n;i++) { if(str[i]==‘A‘) s[i]=0; if(str[i]==‘G‘) s[i]=1; if(str[i]==‘C‘) s[i]=2; if(str[i]==‘T‘) s[i]=3; } init(); f[0][0]=1; for(j=0;j<=m;j++) { for(i=0;i<(1<<n);i++) f[(j&1)^1][i]=0; for(i=0;i<(1<<n);i++) f[(j&1^1)][to[i][0]]=(f[j&1^1][to[i][0]]+f[j&1][i])%mod,f[(j&1^1)][to[i][1]]=(f[j&1^1][to[i][1]]+f[j&1][i])%mod,f[(j&1^1)][to[i][2]]=(f[j&1^1][to[i][2]]+f[j&1][i])%mod,f[(j&1^1)][to[i][3]]=(f[j&1^1][to[i][3]]+f[j&1][i])%mod; } for(i=0;i<(1<<n);i++) ans[cnt[i]]=(ans[cnt[i]]+f[m&1][i])%mod; for(i=0;i<=n;i++) printf("%d\n",ans[i]); } int main() { int T; scanf("%d",&T); while(T--) work(); return 0; }