SYSU-10,URAL 1675,容斥原理

我们队没人会做tm数学,心塞

题目大意:对于一个n*m的01矩阵,问有多少种可能是恰好k行l列全为1,其他行列不全为一。

解:首先我们可以枚举哪些行列全唯一,然后把剩余的行列拿出来,等价于求n,m,0,0。然后我们做以下考虑,假设我们已经保证了所有行都不为0,那么每种情况都会被归类于他们恰有i列全为1。所以我们设f[i]为所有全1列数大于i的方案,所以答案等于 total - f[1], total其实就是C(m,0)* (2^m-1)^n。

递归考虑f[1],f[1] = total2 - f[2]。如此递归直到f[m] = 0。把式子结合起来,就是:

  ans = C(m,0)* (2^m-1)^n - C(m,1)* (2^(m-1)-1)^n + C(m,2)* (2^(m-2)-1)^n ............

(我是无法理解为何是容斥原理,形式很像,各种直觉上来说也是,但是我没办法把他化成集合与的加加减减这种形式)

 

 

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 
 7 using namespace std;
 8 
 9 #define MAXN 111111
10 #define LL long long
11 
12 const LL MOD = 1e9 + 7;
13 
14 LL poww[MAXN], inv[MAXN];
15 
16 int n, m, k, l;
17 
18 LL quick_pow(LL a, LL b) {
19     LL res = 1, base = a;
20     while (b > 0) {
21         if (b&1) res = (res * base) % MOD;
22         base = (base * base ) % MOD;
23         b >>= 1;
24     }
25     return res;
26 }
27 
28 void pre() {
29     poww[0] = 1;
30     inv[0] = 1;
31     for (int i = 1; i < MAXN; ++i) {
32         poww[i] = poww[i-1] * i % MOD;
33         inv[i] = quick_pow(poww[i], MOD - 2);
34     }
35 }
36 
37 #define C(n,m) ((m)>(n)?0:(poww[n]*inv[m]%MOD)*inv[n-m]%MOD)
38 
39 LL calc(int n, int m) {
40     LL res = 0;
41     for (int i = m, k = 1; i >= 0; --i, k = -k) {
42         res += (MOD + k * (C(m, i) * quick_pow(quick_pow(2, i) - 1, n)));
43         res %= MOD;
44     }
45     return res;
46 }
47 
48 int main() {
49     pre();
50     while (scanf("%d%d%d%d", &n, &m, &k, &l) == 4) {
51         LL ans = (C(n, k) * C(m, l) % MOD * calc(n - k, m - l) % MOD) + MOD;
52         cout << ans % MOD << endl;
53     }
54     return 0;
55 }
URAL 1675

 

posted @ 2016-08-11 10:31  F.D.His.D  阅读(...)  评论(...编辑  收藏