HDU-5155-Harry And Magic Box(容斥)
这道题是容斥+快速幂
这道题跟我前几天做的CF上面一道题差不多。CFRound 86E题
题目大意:n * m的网格点上面有宝石jewel,其中这些网格点上面,哈里从左侧面看,可以看到每一行都闪闪发光,说明这个网格上每行都至少有一个宝石;哈里从前面看网格,可以看到每一列上都闪闪发光,说明这个网格点上每列都至少有一个宝石。
问有多少种不同的方案满足题目每行和每列都至少有一个宝石的情况。
答案mod 1e9 + 7;(自从上次遇到过一个1e8 + 7的时候,我再也不敢自作主张统一认为都是1e9 + 7了。)
本题思路:这道题我们用容斥来解决。
我们规定:f(x)代表至少有x列一个钻石也没有的情况。
那么我们先选定x列没有宝石,方案数是(x, m);从总的m列中选取x列一个宝石都不放。
那么对于其余的列数即m - x列:随意放不放宝石,放与不放两种选择,那么就是2^(m - x)次方的情况。我们需要减掉全都没有放宝石的情况。于是就-1。
在这些情况下,每一种情况对应着n行的选择,即(2^(m-x) - 1)^n;
然后用容斥:
f(0) - f(1) + f(2) - f(3)…一直到m
简单解释一下:f(0)至少有0列一个钻石也没有是总的情况。
然后f(1)代表至少有1列一个钻石也没有
f(2)代表至少有2列一个钻石也没有
因为减去了f(1),后来加上f(2);
假设是第a列和第b列一个钻石也没有,那么我们在d(1)中已经减去了这种情况,之后我们通过f(2)加回来。
减去f(3);f(3)代表至少有3列一个钻石也没有,假设这三列是x, y, z;
那么x, y; x, z; y, z这三种情况是两列都没有钻石的,我们在f(2)加了一次,需要在f(3)情况中减掉。
…这样下去,也就对应着计数是减,偶数是加。
总体思路说完啦~
然后就是组合部分,题目数据范围在50以内,所以我们可以预处理出组合数,不进行预处理其实也行。反正不是很大。然后计算幂的时候用快速幂计算即可。
记得取模哦~
代码部分:
#include <bits/stdc++.h>
using namespace std;
const int mod = 1000000007;
const int N = 55;
typedef long long ll;
ll c[N][N];
int n, m;
void init()
{
c[0][0] = 1;
for (int i = 1; i <= 50; i++)
{
c[i][0] = c[i][i] = 1;
}
for (int i = 2; i <= 50; i++)
{
for (int j = 1; j < i; j++)
{
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
}
}
ll npower(ll a, int n)
{
ll res = 1;
while (n)
{
if (n & 1)
{
res = res * a % mod;
}
a = a * a % mod;
n >>= 1;
}
return res;
}
int main()
{
init();
while (~scanf ("%d%d", &n, &m))
{
ll ans = 0;
for (int i = 0; i <= m; i++)
{
ll t = c[m][i] * npower(npower(2, m - i) - 1, n) % mod;
if (i & 1)
{
ans = (ans + mod - t) % mod;
}
else
{
ans = (ans + t) % mod;
}
}
cout << ans % mod << endl;
}
return 0;
}