上午考试的时候AK了,看代码还挺短的,于是学习了一下DP套DP,感觉挺傻逼的
考虑求LCS那个DP,我们发现对于固定的i和任意的j,f[i][j]最多只能和f[i-1][j]有关,不可能和f[i-2][j]或者更往前的DP值有关
并且f[i][j]要么和f[i][j-1]相等,要么等于f[i][j-1]+1
那么我们可以状压这个是否比前一个大1,然后g[i][j]表示长度为i,跑LCS的DP之后f[n]的状态为j的串的个数
那么枚举在最后添加什么字符,可以转移到新的状态
就完了
感觉这个题解和网上别的题解都不是特别清晰的样子……自己体会一下吧
#include<iostream>
#include<cstring>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<map>
using namespace std;
#define MAXN 20
#define MAXM 32768
#define eps 1e-8
#define ll long long
#define MOD 1000000007
#define INF 1000000000
#define lb(x) (x&-x)
char S[MAXN];
int M;
int trans[MAXM][4];
int f[MAXM],g[MAXM];
int c[MAXM];
int ans[MAXN];
int n,m;
int main(){
int i,j,k;
int tmp;
for(i=1;i<MAXM;i++){
c[i]=c[i-lb(i)]+1;
}
scanf("%d",&tmp);
while(tmp--){
scanf("%s%d",S+1,&n);
m=strlen(S+1);
M=1<<m;
for(i=1;i<=m;i++){
if(S[i]=='A'){
S[i]=0;
}
if(S[i]=='G'){
S[i]=1;
}
if(S[i]=='C'){
S[i]=2;
}
if(S[i]=='T'){
S[i]=3;
}
}
memset(trans,0,sizeof(trans));
for(i=0;i<M;i++){
for(j=0;j<4;j++){
int nw=0;
int u=0,d=0;
for(k=1;k<=m;k++){
int nd=d+((i>>k-1)&1);
int nu=max(u,nd);
if(S[k]==j){
nu=max(nu,d+1);
}
if(nu>u){
nw+=1<<k-1;
}
u=nu;
d=nd;
}
trans[i][j]=nw;
}
}
memset(f,0,sizeof(f));
f[0]=1;
for(i=1;i<=n;i++){
memset(g,0,sizeof(g));
for(j=0;j<M;j++){
for(k=0;k<4;k++){
(g[trans[j][k]]+=f[j])%=MOD;
}
}
memcpy(f,g,sizeof(f));
}
memset(ans,0,sizeof(ans));
for(i=0;i<M;i++){
(ans[c[i]]+=f[i])%=MOD;
}
for(i=0;i<=m;i++){
printf("%d\n",ans[i]);
}
}
return 0;
}
/*
*/