zoukankan      html  css  js  c++  java
  • BZOJ3294 CQOI2011放棋子(动态规划)

      可以看做棋子放在某个位置后该种颜色就占领了那一行一列。行列间彼此没有区别。

      于是可以设f[i][j][k]表示前k种棋子占领了i行j列的方案数。转移时枚举第k种棋子占领几行几列。注意行列间是有序的,要乘上一个组合数。这里f[i][j][k]可以是在原棋盘选i行j列占领的方案数,也可以是占领i行j列棋盘的方案数,如果是第二种最后统计答案的时候还要乘上个组合数,转移略有不同但没有本质区别。我们还需要计算出k个棋子占领i行j列中的方案数才能转移。

      考虑怎么求这个东西。设其为g[i][j][k]。不妨把行列尽量往左往上移,可以发现棋子只能放置在其重合区域,也就是一个i*j的棋盘。使得这里面每行每列都有棋子就可以了。

      然而还是不太好算。考虑求存在某一行或某一列没有棋子的方案数,那么可以枚举其中有几行几列是空的转移。于是可得g[i][j][k]=C(i*j,k)-Σg[x][y][k]*C(i,x)*C(j,y) (x+y<i+j)。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define P 1000000009
    #define N 31
    #define K 11
    int n,m,c,l,a[K],f[K][N][N],g[K][N][N],ans=0;
    int fac[N*N],inv[N*N],C[N*N][N*N];
    void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj3294.in","r",stdin);
        freopen("bzoj3294.out","w",stdout);
        const char LL[]="%I64d";
    #else
        const char LL[]="%lld";
    #endif
        n=read(),m=read(),c=read();
        for (int i=1;i<=c;i++) a[i]=read();
        C[1][0]=C[1][1]=1;
        for (int i=2;i<=n*m;i++)
        {
            C[i][0]=C[i][i]=1;
            for (int j=1;j<i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
        }
        for (int k=1;k<=c;k++)
            for (int i=1;i<=n;i++)
                for (int j=1;j<=m;j++)
                if (i*j>=a[k])
                {
                    g[k][i][j]=C[i*j][a[k]];
                    for (int x=1;x<=i;x++)
                        for (int y=1;y<=j;y++)
                        if (x<i||y<j)
                        inc(g[k][i][j],P-1ll*C[i][x]*C[j][y]%P*g[k][x][y]%P);
                }
        f[0][0][0]=1;
        for (int k=1;k<=c;k++)
            for (int i=k;i<=n;i++)
                for (int j=k;j<=m;j++)
                if (i*j>=a[k])
                    for (int x=1;x<=i-k+1;x++)
                        for (int y=1;y<=j-k+1;y++)
                        inc(f[k][i][j],1ll*f[k-1][i-x][j-y]*g[k][x][y]%P*C[n-i+x][x]%P*C[m-j+y][y]%P);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            inc(ans,f[c][i][j]);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    IE6-9中tbody的innerHTML不能赋值bug
    matchesSelector及低版本IE中对该方法的实现
    JavaScript日期组件的实现
    IE6/7/8中parseInt第一个参数为非法八进制字符串且第二个参数不传时返回值为0
    子程序设计原则
    仅IE6中链接A的href为javascript协议时不能在当前页面跳转
    JavaScript获取图片的原始尺寸
    JavaScript判断图片是否加载完成的三种方式
    Mac OS X 快捷键
    IE6-8中Date不支持toISOString方法
  • 原文地址:https://www.cnblogs.com/Gloid/p/9458177.html
Copyright © 2011-2022 走看看