• 【BZOJ3294】放棋子(动态规划,容斥,组合数学)


    【BZOJ3294】放棋子(动态规划,容斥,组合数学)

    题面

    BZOJ
    洛谷

    题解

    如果某一行某一列被某一种颜色给占了,那么在考虑其他行的时候可以直接把这些行和这些列给丢掉。
    那么我们就可以写出一个(dp)
    (f[i][r][c])表示考虑了前(i)种颜色,还剩下(r)(c)列没被染色。
    那么转移的时候枚举一下当前颜色染了(a)(b)列转移就好了。
    但是问题来了,怎么计算用(K)个棋子恰好覆盖(a)(b)列的方案数呢?
    恰好很不好算,那么我们换一下,至多覆盖了(a)(b)列的方案数。
    那么这个很容易算出来是(C_{ab}^{K})
    那么我们可以容斥计算恰好覆盖了(a)(b)列的方案数。
    我们在计算(a,b)的时候就已经可以算出来恰好覆盖了(l,l<a)(r,r<b)列的方案数,
    那么直接拿总数减去不合法的就好了。
    接下来就是一个很简单的(dp)了,稍微用组合数算一下即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define MOD 1000000009
    #define MAX 35
    inline int read()
    {
        int x=0;bool t=false;char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=true,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return t?-x:x;
    }
    void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
    int n,m,c,ans;
    int f[MAX][MAX][MAX],a[MAX];
    int jc[MAX*MAX],jv[MAX*MAX],inv[MAX*MAX];
    int g[MAX][MAX][MAX];
    int C(int n,int m){if(m>n)return 0;return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
    int main()
    {
    	n=read();m=read();c=read();
    	for(int i=1;i<=c;++i)a[i]=read();
    	jc[0]=inv[0]=inv[1]=jv[0]=1;
    	for(int i=1;i<=n*m;++i)jc[i]=1ll*jc[i-1]*i%MOD;
    	for(int i=2;i<=n*m;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<=n*m;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
    	for(int i=1;i<=c;++i)
    		for(int j=1;j<=n;++j)
    			for(int k=1;k<=m;++k)
    			{
    				if(j*k<a[i])continue;
    				g[i][j][k]=C(j*k,a[i]);
    				for(int l=1;l<=j;++l)
    					for(int r=1;r<=k;++r)
    						if(l!=j||r!=k)add(g[i][j][k],MOD-1ll*C(j,l)*C(k,r)%MOD*g[i][l][r]%MOD);
    			}
    	f[0][0][0]=1;
    	for(int i=1;i<=c;++i)
    		for(int j=1;j<=n;++j)
    			for(int k=1;k<=m;++k)
    				for(int a=1;a<=j;++a)
    					for(int b=1;b<=k;++b)
    						add(f[i][j][k],1ll*g[i][a][b]*f[i-1][j-a][k-b]%MOD*C(n-j+a,a)%MOD*(C(m-k+b,b))%MOD);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)add(ans,f[c][i][j]);
    	printf("%d
    ",ans);
    	return 0;
    }
    						
    
    
  • 相关阅读:
    javascript 文档标题滚动 实例
    Unity3D初学之2D动画制
    Uni2D 入门 -- Skeletal Animation
    Uni2D 入门 -- Asset Table
    Uni2D 入门 -- Atlas转载 http://blog.csdn.net/kakashi8841/article/details/17588095
    Uni2D 入门 -- Animation Clip 和 Animation API
    Uni2D入门
    将博客搬至CSDN
    unity 2048Game
    c#单例模式
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9416457.html
Copyright © 2020-2023  润新知