cf111D Petya and Coloring 组合数学,二项式反演

http://codeforces.com/contest/111/problem/D

 

Little Petya loves counting. He wants to count the number of ways to paint a rectangular checkered board of size n × m (n rows, m columns) in k colors. Besides, the coloring should have the following property: for any vertical line that passes along the grid lines and divides the board in two non-empty parts the number of distinct colors in both these parts should be the same. Help Petya to count these colorings.

Input

The first line contains space-separated integers n, m and k (1 ≤ n, m ≤ 1000, 1 ≤ k ≤ 106) — the board's vertical and horizontal sizes and the number of colors respectively.

Output

Print the answer to the problem. As the answer can be quite a large number, you should print it modulo 109 + 7 (1000000007).

Examples
Input
2 2 1
Output
1
Input
2 2 2
Output
8
Input
3 2 2
Output
40




题意:
给出一个 n*m 的矩阵,用sum种颜色染色
满足:任意一条竖直线(纵线)把矩阵划分成的2个部分,2个部分的不同的颜色数相同
求方案数
n,m <= 10^3,sum <= 10^6

solution:
注意到n,m的范围不大

显然有以下性质:
1.第1列和第m列的颜色数一定相等
2.2~m-1列的颜色只能从1,m列的颜色的交集中选择

m=1的时候,特殊处理,ans=k^n
m>1的时候,我们只需要考虑1,m列的颜色选择还有交集大小

预处理g[i]表示恰好用i种颜色涂满n个格子的方案数
(此时n是一个常量)

如果用递推式,求g[i]需要O(n^2),求g数组需要O(n^3),tle
考虑二项式反演求g数组:
设h(i)表示用i种颜色染n个格子的方案数,则h(i) = i^n
g(i)表示恰好用i种颜色染n个格子的方案数,
有:h(y) = sigma(i=0,i<=y)(C(y,i)*g(i))
则:g(y) = sigma(i=0,i<=y)((-1)^(y-i) * C(y,i) * h(i))
     = sigma(i=0,i<=y)((-1)^(y-i) * C(y,i) * i^n)

这样求g[i]需要O(nlogn),求g数组需要O(n^2*logn)
当然也可以优化到O(n^2)求g数组

主要的预处理部分搞定了,然后就是答案了
退下公式,得到:
ans = sigma(j=0,j<=min(n,sum))C(sum,j) * j^(m*n-2*n) *
    (sigma(i=0,i<=min(n-j,(sum-j)/2))(C(sum-j,i)*C(sum-j-i,i)*g(i+j)^2))



 1                                             
 2   //File Name: cf111D.cpp
 3   //Author: long
 4   //Mail: 736726758@qq.com
 5   //Created Time: 2016年05月16日 星期一 01时13分24秒
 6                                    
 7 
 8 #include <stdio.h>
 9 #include <algorithm>
10 #include <iostream>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <math.h>
14 
15 #define LL long long
16 
17 using namespace std;
18 
19 const int MAXN = 1000 + 3;
20 const int MAXM = 1000000 + 3;
21 const int MOD = (int)1e9 + 7;
22 
23 LL jie[MAXM];
24 LL g[MAXN];
25 
26 LL qp(LL x,LL y){
27     LL res = 1;
28     while(y){
29         if(y & 1) res = res * x % MOD;
30         x = x * x % MOD;
31         y >>= 1;
32     }
33     return res;
34 }
35 
36 LL get_c(LL x,LL y){
37     if(x < y) return 0;
38     if(x == y || y == 0) return 1;
39     return jie[x] * qp(jie[y] * jie[x - y] % MOD,MOD - 2) % MOD;
40 }
41 
42 void init(int sum,int n){
43     jie[0] = 1;
44     for(int i=1;i<MAXM;i++)
45         jie[i] = jie[i-1] * i % MOD;
46     int ma = min(sum,n);
47     LL now;
48     for(int i=0;i<=ma;i++){
49         for(int k=0;k<=i;k++){
50             now = get_c(i,k) * qp(k,n) % MOD;
51             if((i - k) % 2)
52                 g[i] = (g[i] - now + MOD) % MOD;
53             else
54                 g[i] = (g[i] + now) % MOD;
55         }
56     }
57 }
58 
59 LL solve(int n,int m,int sum){
60     if(m == 1) return qp(sum,n);
61     init(sum,n);
62     LL ans = 0,now,tmp;
63     int ma = min(sum,n);
64     for(int j=0,ma2;j<=ma;j++){
65         now = 0;
66         ma2 = min(n - j,(sum - j) / 2);
67         for(int i=0;i<=ma2;i++){
68             (now += jie[sum-j] * qp(jie[sum-j-2*i]*jie[i]%MOD*jie[i]%MOD,MOD - 2) % MOD
69                 * g[i+j] % MOD * g[i+j] % MOD) %= MOD;
70         }
71         tmp = qp(j,(m - 2) * n) % MOD;
72         (ans += get_c(sum,j) * tmp % MOD * now % MOD) %= MOD;
73         //cout << j << " " <<ans << endl;
74     }
75     return ans;
76 }
77 
78 int main(){
79     int n,m,k;
80     scanf("%d %d %d",&n,&m,&k);
81     printf("%d\n",(int)solve(n,m,k));
82     return 0;
83 }

 






转载于:https://www.cnblogs.com/-maybe/p/5499202.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值