zoukankan      html  css  js  c++  java
  • luogu P4590 [TJOI2018]游园会 dp套dp

    LINK:游园会

    容易想到 设(f[i][j][k][l])前i个字符 j表示状压的w个字符状态为j 长度<=k 匹配到了NOI的第l个位置的方案数.

    不过只能得到30分。

    考虑优化 其实优化就只能优化如何快速得到LCS 这个问题 (3^15cdot 15)的状态量无法很难接受。

    考虑降低这个状态量。考虑如果在一个自动机上 那么我们这个状态就可以表示匹配到了自动机上某个节点。

    不过最长公共子序列自动机 并不存在。

    考虑人为构造这个东西 考虑求两个串的最长公共子序列的dp.

    (dp_{i,j})表示A串前i个字符B串前j个字符的最大长度.

    容易得到转移:(dp_{i,j}=max(dp_{i-1,j},dp{i,j-1},dp_{i-1,j-1}+[A_i==B_j]))

    那么其实只要知道(dp_i-1)这个数组和当前这个字符(A_i)就可以推向下一个字符。

    进一步的 以(dp_i)为最长公共子序列的节点 那么每次转移只需要枚举下一个字符是谁 就可以很容易的重新得到新的LCS的状态和长度.

    这样就可以把上述的那么大的状态量压缩成了这样的dp数组 不过直接存一个数组是需要hash的。

    可以观察得到 (dp_i)是不降的 可以将其差分就得到了一个二进制串 最终状态量为(2^w) 可以通过此题.

    const int MAXN=1010,maxn=35010;
    int n,k,u,maxx;
    int f[2][maxn][3];
    char a[MAXN];
    int g[2][MAXN],sum[maxn],ans[MAXN];
    inline void add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
    inline void jy(int s)
    {
    	rep(1,k,i)g[0][i]=s>>i-1&1;
    	rep(1,k,i)g[0][i]+=g[0][i-1];
    }
    inline int ys()
    {
    	int S=0;
    	rep(1,k,i)if(g[1][i]-g[1][i-1])S|=1<<(i-1);
    	return S;
    }
    inline void update(int s,int l,char c,int w)
    {
    	jy(s);
    	rep(1,k,i)
    	{
    		g[1][i]=max(g[0][i],g[1][i-1]);
    		if(c==a[i])g[1][i]=max(g[1][i],g[0][i-1]+1);
    	}
    	int j=ys();add(f[u][j][l],w);
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	gt(n);gt(k);gc(a);
    	maxx=1<<k;--maxx;
    	f[u][0][0]=1;
    	rep(1,n,i)
    	{
    		u=u^1;
    		rep(0,maxx,j)rep(0,2,k)f[u][j][k]=0;
    		rep(0,maxx,j)
    		{
    			if(f[u^1][j][0])
    			{
    				update(j,1,'N',f[u^1][j][0]);
    				update(j,0,'O',f[u^1][j][0]);
    				update(j,0,'I',f[u^1][j][0]);
    			}
    			if(f[u^1][j][1])
    			{
    				update(j,1,'N',f[u^1][j][1]);
    				update(j,2,'O',f[u^1][j][1]);
    				update(j,0,'I',f[u^1][j][1]);
    			}
    			if(f[u^1][j][2])
    			{
    				update(j,1,'N',f[u^1][j][2]);
    				update(j,0,'O',f[u^1][j][2]);
    			}
    		}
    	}
    	rep(0,maxx,i)
    	{
    		sum[i]=sum[i>>1]+(i&1);
    		rep(0,2,j)add(ans[sum[i]],f[u][i][j]);
    	}
    	rep(0,k,i)put(ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    解决PKIX:unable to find valid certification path to requested target 的问题
    Linux 上的常用文件传输方式介绍与比较
    用VNC远程图形化连接Linux桌面的配置方法
    红帽中出现”This system is not registered with RHN”的解决方案
    linux安装时出现your cpu does not support long mode的解决方法
    CentOS SSH配置
    es6扩展运算符及rest运算符总结
    es6解构赋值总结
    tortoisegit安装、clon、推送
    es6环境搭建
  • 原文地址:https://www.cnblogs.com/chdy/p/13138270.html
Copyright © 2011-2022 走看看