zoukankan      html  css  js  c++  java
  • codeforces111D. Petya and Coloring(组合数学,计数问题)

    传送门:

    解题思路:

    要求一条直线分割矩阵时左右颜色数一样,那么就说明一个问题。
    直线左右移动时是不会改变左右矩阵的颜色集合的。
    所以说明:2~m-1列的颜色集一定属于第一列与第m列颜色集的交集。
    而且第一列与第m列颜色集大小相等。
    显然需要预处理n个点m种颜色的方案数,设为$g(i,j)$
    这样,只需要确定第一列和最后一列颜色集,假设交集是$i$种颜色,
    就可以算出中间的颜色方案数:$i^{n*(m-2)}$
    假设两边颜色个数都是$j$($jge i$)那么两边颜色的答案($(g(n,j)j!)^2$)
    这$i$种颜色共有$C_k^i$种选法,两边各$j$种颜色,且只有$i$种颜色相同的方案就是:
    $Large C_k^iC_{k-i}^{2(j-i)}C_{2(j-i)}^{j-i}$
    那么答案就是
    $Largesumlimits_{i=1}^{n}sumlimits_{j=i}^{n}C_k^iC_{k-i}^{2(j-i)}C_{2(j-i)}^{j-i}{(g(n,j)j!)^2}{i^{n(m-2)}}$
    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 typedef long long lnt;
     5 const lnt mod=1000000007;
     6 lnt g[1010][1010];
     7 lnt fac[1000010];
     8 lnt inv[1000010];
     9 int n,m,k;
    10 lnt ans;
    11 lnt ksm(lnt a,lnt b)
    12 {
    13     lnt ans=1;
    14     while(b)
    15     {
    16         if(b&1)ans=ans*a%mod;
    17         a=a*a%mod;
    18         b=b/2;
    19     }
    20     return ans;
    21 }
    22 lnt C(int x,int y)
    23 {
    24     if(y>x)return 0;
    25     return fac[x]*inv[y]%mod*inv[x-y]%mod; 
    26 }
    27 lnt squ(lnt x)
    28 {
    29     return x*x%mod;
    30 }
    31 int main()
    32 {
    33     g[0][0]=1;
    34     fac[0]=inv[0]=fac[1]=inv[1]=1;
    35     for(int i=2;i<=1000000;i++)
    36     {
    37         fac[i]=(fac[i-1]*i)%mod;
    38         inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    39     }
    40     for(int i=1;i<=1000000;i++)inv[i]=inv[i]*inv[i-1]%mod;
    41     scanf("%d%d%d",&n,&m,&k);
    42     if(m==1)
    43     {
    44         printf("%I64d
    ",ksm(k,n));
    45         return 0;
    46     }
    47     for(int i=1;i<=n;i++)
    48     {
    49         for(int j=1;j<=i&&j<=k;j++)
    50         {
    51             g[i][j]=(g[i-1][j-1]+g[i-1][j]*j)%mod;
    52         }
    53     }
    54     for(int i=0;i<=n;i++)
    55     {
    56         lnt tmp=ksm(i,n*(m-2))*C(k,i)%mod;
    57         for(int j=i;j<=n;j++)
    58         {
    59             ans=(ans+tmp*C(k-i,(j-i)*2)%mod*C((j-i)*2,j-i)%mod*squ(g[n][j]*fac[j]%mod)%mod)%mod;
    60         }
    61     }
    62     printf("%I64d
    ",(ans%mod+mod)%mod);
    63     return 0;
    64 }
  • 相关阅读:
    十大经典排序算法最强总结(含Java、Python码实现)
    数据库查询优化的12种方式
    开发环境、测试环境、预发布环境、生产环境的区别
    阅站无数的我,只推荐下面这些让你起飞的
    访问控制符
    继承的意义
    数组继承的意义
    java 俄罗斯方块
    类和面向对象
    随机生成数组游戏
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/10389476.html
Copyright © 2011-2022 走看看