• 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;
    }
    
  • 相关阅读:
    Shell之sed用法 转滴
    再议mysql 主从配置
    CentOS 如何将.deb 文件 转换.rpm
    scp命令[转]
    安装samba服务器
    xdebug影响php运行速度
    PHP中VC6、VC9、TS、NTS版本的区别与用法详解
    将Centos的yum源更换为国内的阿里云源
    centos网卡错误Device eth0 does not seem to be present
    虚拟机VirtualBox中centos6.5网络设置
  • 原文地址:https://www.cnblogs.com/chdy/p/13138270.html
Copyright © 2020-2023  润新知