P10614 BZOJ3864 Hero meet devil 题解
_fairytale_ · · 题解
upd 2024.9.5:感谢 @Auferstanden 指出的代码错误,发现是 ans[0] 忘清空了,已修改。
欸这题啥时候登陆洛谷了,抢下第一篇题解!
经典 DP 套 DP 题目。
这道题的内层 DP 是 LCS,我们不妨想 LCS 的转移方程:
设
因此一个朴素的想法就是,设
其实到这里已经可以了,这个 DP 看着状态数很恐怖,实际上状态数很少。
考虑在
而且既然发现差分数组只有
#include<bits/stdc++.h>
bool Mst;
#define in(S,i) (((S)>>((i)-1))&1)
#define rep(x,qwq,qaq) for(int (x)=(qwq);(x)<=(qaq);++(x))
using namespace std;
#define mod 1000000007
int T;
int n,m;
string s;
#define maxm 1010
int f[maxm][(1<<15)];
int g[20],h[20];
void add(int &x,int y) {
x+=y;
if(x>=mod)x-=mod;
}
int a[20];
int append(int S,int nxt) {
rep(i,1,n)g[i]=g[i-1]+in(S,i);
rep(i,1,n) {
if(a[i]==nxt)h[i]=g[i-1]+1;
else h[i]=max({h[i-1],g[i]});
}
int reS=0;
rep(i,1,n)reS+=(1<<(i-1))*(h[i]-h[i-1]);
return reS;
}
int ans[20];
int nxt[(1<<15)][5];
void solve() {
cin>>s>>m;
n=s.length();
s=" "+s;
rep(i,1,n) {
switch(s[i]) {
case 'A':
a[i]=1;
break;
case 'C':
a[i]=2;
break;
case 'G':
a[i]=3;
break;
case 'T':
a[i]=4;
break;
}
}
rep(S,0,(1<<n)-1)rep(i,1,4)nxt[S][i]=append(S,i);
f[0][0]=1;
rep(i,0,m-1) {
rep(S,0,(1<<n)-1) {
if(f[i][S]==0)continue;
add(f[i+1][nxt[S][1]],f[i][S]);
add(f[i+1][nxt[S][2]],f[i][S]);
add(f[i+1][nxt[S][3]],f[i][S]);
add(f[i+1][nxt[S][4]],f[i][S]);
f[i][S]=0;
}
}
rep(i,0,n)ans[i]=0;
rep(S,0,(1<<n)-1) {
add(ans[__builtin_popcount(S)],f[m][S]);
f[m][S]=0;
}
rep(i,0,n)cout<<ans[i]<<'\n';
}
bool Med;
signed main() {
cerr<<(&Mst-&Med)/1024.0/1024.0<<" MB\n";
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--)solve();
return 0;
}