• Luogu P5664 Emiya 家今天的饭


    重做下去年的CSP题找找感觉,去年D1T2写可持久化线段树上二分的悲惨经历让我对D1T2充满了厌恶(好吧其实是正解在简单都懒得写了),因此就来改这个去年没调出来的DP了

    首先这个主要食材占一半一眼容斥,因此我们大体思路就有了

    先求出不管这个限制的总方案数,设(f_{i,j})表示前(i)种方法中做了(j)道菜的方案数,记录一个每行的和显然可以(O(n^2))转移

    考虑大力枚举哪个食材(p)超过了(lfloor frac{k}{2} floor),显然可以再做一次DP,设(g_{i,j,k})表示前(i)种方法中做了(j)道菜的方案数,其中有(k)道菜使用了食材(p),转移显然

    但这样总复杂度是(O(n^3m))无法通过,放一下代码意思一下

    #include<cstdio>
    #include<cstring>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=105,M=2005,mod=998244353;
    int n,m,a[N][M],f[N][N],g[N][N][N],sum[N],ans;
    int main()
    {
    	RI i,j,k,p; for (scanf("%d%d",&n,&m),i=1;i<=n;++i)
    	for (j=1;j<=m;++j) scanf("%d",&a[i][j]),(sum[i]+=a[i][j])%=mod;
    	for (f[0][0]=1,i=1;i<=n;++i) for (j=0;j<=i;++j)
    	f[i][j]=(f[i-1][j]+(j?1LL*f[i-1][j-1]*sum[i]%mod:0))%mod;
    	for (i=1;i<=n;++i) (ans+=f[n][i])%=mod;
    	for (p=1;p<=m;++p)
    	{
    		for (g[0][0][0]=i=1;i<=n;++i) for (j=0;j<=i;++j) for (k=0;k<=j;++k)
    		g[i][j][k]=(1LL*g[i-1][j][k]+(j?1LL*g[i-1][j-1][k]:0)*(sum[i]-a[i][p]+mod)%mod+
    		(j&&k?1LL*g[i-1][j-1][k-1]*a[i][p]%mod:0))%mod; 
    		for (i=1;i<=n;++i) for (j=(i>>1)+1;j<=n;++j) (ans+=mod-g[n][i][j])%=mod;
    	}
    	return printf("%d",ans),0;
    }
    

    我们仔细观察一下转移方程发现我们只需要知道后两维的差即可(话说这一年做的AGC中有太多这样的套路了),因此直接压成一维总复杂度就是(O(n^2m))的了

    #include<cstdio>
    #include<cstring>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=105,M=2005,mod=998244353;
    int n,m,a[N][M],f[N][N],g[N][N<<1],sum[N],ans;
    int main()
    {
    	RI i,j,p; for (scanf("%d%d",&n,&m),i=1;i<=n;++i)
    	for (j=1;j<=m;++j) scanf("%d",&a[i][j]),(sum[i]+=a[i][j])%=mod;
    	for (f[0][0]=1,i=1;i<=n;++i) for (j=0;j<=i;++j)
    	f[i][j]=(f[i-1][j]+(j?1LL*f[i-1][j-1]*sum[i]%mod:0))%mod;
    	for (i=1;i<=n;++i) (ans+=f[n][i])%=mod;
    	for (p=1;p<=m;++p)
    	{
    		for (g[0][n]=i=1;i<=n;++i) for (j=-i;j<=i;++j)
    		g[i][n+j]=(1LL*g[i-1][n+j]+1LL*g[i-1][n+j-1]*a[i][p]%mod+
    		1LL*g[i-1][n+j+1]*(sum[i]-a[i][p]+mod)%mod)%mod;
    		for (i=1;i<=n;++i) (ans+=mod-g[n][n+i])%=mod;
    	}
    	return printf("%d",ans),0;
    }
    
  • 相关阅读:
    Hdu 1429 胜利大逃亡(续) (bfs+状态压缩)
    Vijos 1456 最小总代价 (状压dp)
    洛谷 P1313 计算系数 (二项式定理)
    洛谷 P1134 阶乘问题
    EINTR错误
    TCP和UDP协议的应用/参数查看
    BAT面经
    高级环境编程要看的
    UDP丢包和无序 问题的解决方法
    tcp/ip
  • 原文地址:https://www.cnblogs.com/cjjsb/p/13927950.html
Copyright © 2020-2023  润新知