zoukankan      html  css  js  c++  java
  • [CQOI2011]放棋子

    https://www.zybuluo.com/ysner/note/1246107

    题面

    在一个(n)(m)列的棋盘里放(c)种不同色的棋子(每种有(c_i)个),使得每个格子最多放一个棋子,且不同
    颜色的棋子不能在同一行或者同一列。有多少种方法?

    (n,mleq30,cleq10)

    解析

    被细节坑惨系列
    题目输入了(n,m,c)这三个量,于是(DP)数组中也要包含这三个量。(???)
    (f[i][j][k])表示前(k)种棋子放了任意(i)行、(j)列。
    决策是:在哪些位置填同种颜色的棋子。

    于是枚举上一个状态的(i,j)(表示为(l,r))。上一状态(k'=k-1)
    如果设(g[i][j][k])表示(k)个同颜色棋子放了任意(i)行、(j)列的方案数,
    则$$f[i][j][k]+=f[l][r][k-1]g[i][j][k]C_{n-l}^{i-l}*C_{m-r}^{i-r}$$
    (C_{n-l}^{i-l})表示在空着的(n-l)行中选出(i-l)行放棋子。(C_{m-r}^{i-r})同理。

    怎么求(g[i][j][k])呢?(卡壳处)
    直接求求不出,可以换一种思路——容斥,用所有方案减去不合法方案(即有行列没填,或者可以理解为合法的局部方案)。

    [g[i][j]=C_{i*j}^{k}-g[l][r]*C_{i}^l*C_{j}^r$$依式转移即可。 由于只要放完棋子而不一定要摆满行列。 $$ans=sum_{i=1}^{m}sum_{j=1}^{n}f[i][j][c]]

    注意事项:

    • 允许一种颜色棋子只放行、不放列的情况。
    • 注意组合数的合法性(即(C_n^m)(ngeq m))
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    #define re register
    #define il inline
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=2005,mod=1e9+9;
    int n,m,c,a[40];
    ll f[40][40][40],g[40][40],C[N][N],ans;
    il ll gi()
    {
      re ll x=0,t=1;
      re char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    int main()
    {
      n=gi();m=gi();c=gi();
      fp(i,1,c) a[i]=gi();
      fp(i,0,2000)
        {
          C[i][0]=1;
          fp(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
        }
      f[0][0][0]=1;
      fp(k,1,c)
        {
          memset(g,0,sizeof(g));//注意到g值只对一种颜色有效
          fp(i,0,n)
        fp(j,0,m)
        if(i*j>=a[k])//...
        {
          g[i][j]=C[i*j][a[k]];
              fp(l,0,i)
            fp(r,0,j)
    	    if(l<i||r<j)//
            g[i][j]=(g[i][j]-g[l][r]*C[i][l]%mod*C[j][r]%mod+mod)%mod;
        }
          fp(i,0,n)
        fp(j,0,m)
        fp(l,0,i)
        fp(r,0,j)
    	if(l<i||r<j)//
        f[i][j][k]=(f[i][j][k]+f[l][r][k-1]*g[i-l][j-r]%mod*C[n-l][i-l]%mod*C[m-r][j-r]%mod+mod)%mod;
        }
      fp(i,1,n) fp(j,1,m) (ans+=f[i][j][c])%=mod;
      printf("%lld
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    【leetcode】106. Construct Binary Tree from Inorder and Postorder Traversal
    【leetcode】105. Construct Binary Tree from Preorder and Inorder Traversal
    【leetcode】236. Lowest Common Ancestor of a Binary Tree
    【leetcode】235. Lowest Common Ancestor of a Binary Search Tree
    【leetcode】352. Data Stream as Disjoint Intervals
    【leetcode】897. Increasing Order Search Tree
    【leetcode】900. RLE Iterator
    BEC listen and translation exercise 26
    BEC listen and translation exercise 25
    BEC listen and translation exercise 24
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9467292.html
Copyright © 2011-2022 走看看