bzoj 3864: Hero meet devil(dp套dp)
Posted bztminamoto
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3864: Hero meet devil(dp套dp)相关的知识,希望对你有一定的参考价值。
题面
给你一个只由(AGCT)组成的字符串(S (|S| ≤ 15)),对于每个(0 ≤ .. ≤ |S|),问
有多少个只由(AGCT)组成的长度为(m(1 ≤ m ≤ 1000))的字符串(T),使得(LCS(T,S)=i)?
题解
老早就听说这个叫做(dp of dp)的神仙了……然而一直没学……
我们先考虑(LCS)是怎么转移的,设(LCS(i,j))表示第一个串到(i),第二个串到(j)为止的最长公共子序列,那么转移为
[ LCS(i,j)=max egin{cases} LCS(i-1,j-1)+1 &S[i]=T[j]LCS(i,j-1)LCS(i-1,j) end{cases} ]
然后我们发现(LCS(i,j))的值和(LCS(i,j-1))的值相差最多不会超过(1)
那么我们把数组的第二维差分一下,再状压成一个二进制序列,然后我们就可以预处理出(to[s][k])表示当前(LCS)状态为(s),加的下一个字符为(k),可以到达的(LCS)状态是什么
然后设(f[i][s])表示当前在第(i)个位置,此时(LCS)状态为(s)的方案数
那么转移方程就是
[f[i][to[s][k]]+=f[i-1][s](k=A,T,G,C)]
边界为(f[0][0]=1)
//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
const char T[15]={"ATGC"};const int N=(1<<15)+5,P=1e9+7;
inline void Add(R int &x,R int y){(x+=y)>=P?x-=P:0;}
char S[19];int to[N][4],sz[N],f[2][N],ans[1005];
int n,m,lim,t;
void init(){
static int d[19],g[19];
fp(s,0,lim-1){
sz[s]=sz[s>>1]+(s&1);
fp(j,0,n-1)d[j+1]=d[j]+(s>>j&1);
fp(k,0,3){
fp(j,1,n){
g[j]=max(g[j-1],d[j]);
T[k]==S[j]?cmax(g[j],d[j-1]+1):0;
}
to[s][k]=0;
fp(j,0,n-1)g[j+1]-g[j]?(to[s][k]|=(1<<j)):0;
}
}
}
int main(){
// freopen("testdata.in","r",stdin);
int cas;scanf("%d",&cas);
while(cas--){
scanf("%s%d",S+1,&m),n=strlen(S+1),lim=(1<<n);
init(),memset(ans,0,4*(n+1)),memset(f,0,sizeof(f));
f[0][0]=1,t=0;
for(R int i=1;i<=m;++i,t^=1){
memset(f[t^1],0,4*lim);
fp(s,0,lim-1)fp(k,0,3)Add(f[t^1][to[s][k]],f[t][s]);
}
fp(s,0,lim-1)Add(ans[sz[s]],f[t][s]);
fp(i,0,n)printf("%d
",ans[i]);
}
return 0;
}
以上是关于bzoj 3864: Hero meet devil(dp套dp)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj千题计划241:bzoj3864: Hero meet devil