[HDOJ 4899] Hero meet devil [动态规划+状态压缩]

来源:互联网 发布:淘宝直播卖的翡翠a货 编辑:程序博客网 时间:2024/06/01 10:09

给一个长度不超过15的字符串S,问长度为m且与S的最长公共子序列为0~len(S)的字符串各有多少个?字符串中只会出现A,C,G,T四种字符。

定义状态dp[i][j],i表示长度为i的字符串,j为压缩了的状态,表示该字符串与串S的前k位的最长公共子序列的长度。注意到任意一个字符串与S的位k为的最长公共子序列的长度,和他与S的前k+1位的最长公共子序列的长度最多只差1,所以可以压缩成一个长度不超过15的01串,表示出那个长度为i的串与S的任意前缀最长公共子序列的长度情况。dp[i][j]存储在在i,j情况下的不同的字符串的个数。

提前预处理出每个j在加上ACTG中的任意一种字符之后会转移到什么状态。最后扫描dp[m][j],求出结果。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int mod=1000000007;inline int getNbits(int x) {int ans=0;while (x) {ans+=x&1;x>>=1;}return ans;}inline void update(int &a,int b) {a+=b;if (a>mod) a-=mod;}char s[16];int ans[16];int nbits[1<<15];int nxt[1<<15][4];int dp[1001][1<<15];int ls,n,m;int getNext(int o,char c) {int tmpdp[16],tmpdp2[16],ans=0,i;tmpdp[0]=0;tmpdp2[0]=0;for (i=0;i<ls;i++) {if (o&1<<i) tmpdp[i+1]=tmpdp[i]+1;else tmpdp[i+1]=tmpdp[i];}for (i=0;i<ls;i++) {if (c==s[i]) tmpdp2[i+1]=tmpdp[i]+1;else tmpdp2[i+1]=max(tmpdp2[i],tmpdp[i+1]);}for (i=0;i<ls;i++) {if (tmpdp2[i+1]!=tmpdp2[i]) ans|=1<<i;}return ans;}void init() {int j;for (j=0;j<n;j++) {nxt[j][0]=getNext(j,'A');nxt[j][1]=getNext(j,'C');nxt[j][2]=getNext(j,'G');nxt[j][3]=getNext(j,'T');}}int main() {int t,i,j;scanf("%d",&t);for (i=0;i<1<<15;i++) nbits[i]=getNbits(i);while (t--) {scanf("%s",s);scanf("%d",&m);ls=strlen(s);n=1<<ls;init();for (i=0;i<=m;i++) for (j=0;j<n;j++)   dp[i][j]=0;dp[0][0]=1;for (i=0;i<m;i++) {for (j=0;j<n;j++) {update(dp[i+1][nxt[j][0]],dp[i][j]);update(dp[i+1][nxt[j][1]],dp[i][j]);update(dp[i+1][nxt[j][2]],dp[i][j]);update(dp[i+1][nxt[j][3]],dp[i][j]);}}memset(ans,0,sizeof(ans));for (j=0;j<n;j++) {update(ans[nbits[j]],dp[m][j]);}for (i=0;i<=ls;i++) {printf("%d\n",ans[i]);}}return 0;}


0 0