您的位置:首页 > 其它

SYSU-10,URAL 1675,容斥原理

2016-08-11 10:31 489 查看
我们队没人会做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 ............

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

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

#define MAXN 111111
#define LL long long

const LL MOD = 1e9 + 7;

LL poww[MAXN], inv[MAXN];

int n, m, k, l;

LL quick_pow(LL a, LL b) {
LL res = 1, base = a;
while (b > 0) {
if (b&1) res = (res * base) % MOD;
base = (base * base ) % MOD;
b >>= 1;
}
return res;
}

void pre() {
poww[0] = 1;
inv[0] = 1;
for (int i = 1; i < MAXN; ++i) {
poww[i] = poww[i-1] * i % MOD;
inv[i] = quick_pow(poww[i], MOD - 2);
}
}

#define C(n,m) ((m)>(n)?0:(poww
*inv[m]%MOD)*inv[n-m]%MOD)

LL calc(int n, int m) {
LL res = 0;
for (int i = m, k = 1; i >= 0; --i, k = -k) {
res += (MOD + k * (C(m, i) * quick_pow(quick_pow(2, i) - 1, n)));
res %= MOD;
}
return res;
}

int main() {
pre();
while (scanf("%d%d%d%d", &n, &m, &k, &l) == 4) {
LL ans = (C(n, k) * C(m, l) % MOD * calc(n - k, m - l) % MOD) + MOD;
cout << ans % MOD << endl;
}
return 0;
}


URAL 1675
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: