我是靠谱客的博主 愤怒凉面,最近开发中收集的这篇文章主要介绍Codeforces 451E 容斥原理,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题意

传送门 Codeforces 451E

题解

多重集的组合数问题。考虑每个盒子花的数量没有限制的情况,那么组合数为
C s + n − 1 n − 1 C_{s+n-1}^{n-1} Cs+n1n1 可以看做在 s + n − 1 s+n-1 s+n1 个位置中插入 n − 1 n-1 n1 个隔板,每个间隔构成了 n n n 个盒子取数的情况。需要从没有限制的取法中减去超出限制的取法的数量。设 A i A_i Ai 代表取法中从第 i i i 个盒子中取出超过限制(即大于 f i f_i fi)的花的取法,那么答案为
C s + n − 1 n − 1 − ∣ ⋃ i = 1 n A i ∣ C_{s+n-1}^{n-1}-|bigcuplimits_{i=1}^{n}A_i | Cs+n1n1i=1nAi 根据容斥原理,求解并集的时候需要计算交集。考虑 ∣ A i ∣ |A_i| Ai,预取 f i + 1 f_i+1 fi+1 朵花,其余情况任取,则仍然可以使用无限制情况下多重集组合数的求法,即 C s + n − 1 − ( f i + 1 ) n − 1 C_{s+n-1-(f_i+1)}^{n-1} Cs+n1(fi+1)n1;同理, ∣ A i ∩ A j ∣ |A_icap A_j| AiAj 取法为 C s + n − 1 − ( f i + 1 + f j + 1 ) n − 1 C_{s+n-1-(f_i+1+f_j+1)}^{n-1} Cs+n1(fi+1+fj+1)n1

设从从 n n n 个盒子中取 k k k 个盒子的集合为 S k S_k Sk,那么可以枚举集合, ∣ ∑ k = 0 n S k ∣ = 2 n |sumlimits_{k=0}^{n}S_k|=2^n k=0nSk=2n,集合 S k S_k Sk 对应项为
( − 1 ) k C s + n − 1 − ∑ i ∈ S k ( f i + 1 ) n − 1 (-1)^kC_{s+n-1-sumlimits_{iin S_k}(f_i+1)}^{n-1} (1)kCs+n1iSk(fi+1)n1 考虑到 s s s 的值很大,而 n n n 较小,将组合数写为
C n m = A n m m ! C_{n}^{m}=frac{A_{n}^{m}}{m!} Cnm=m!Anm 此时保证组合数求解复杂度为 O ( n ) O(n) O(n),使用 L u c a s Lucas Lucas 定理防止 l o n g   l o n g long long long long 溢出。总时间复杂度为 O ( n 2 n ) O(n2^n) O(n2n)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 25
const ll mod = 1000000007;
ll n, s, f[maxn], inv[maxn], fv[maxn];
ll C(ll n, ll m)
{
if (n < m)
return 0;
if (m == 0)
return 1;
ll res = 1;
for (ll i = n - m + 1; i <= n; ++i)
res = (res * i) % mod;
return res * fv[m] % mod;
}
ll Lucas(ll n, ll m)
{
if (n < m)
return 0;
if (m == 0)
return 1;
return C(n % mod, m % mod) * Lucas(n / mod, m / mod) % mod;
}
int main()
{
cin >> n >> s;
for (int i = 0; i < n; ++i)
cin >> f[i];
inv[1] = fv[0] = fv[1] = 1;
for (int i = 2; i < n; ++i)
{
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
fv[i] = inv[i] * fv[i - 1] % mod;
}
ll res = 0;
for (int i = 0; i < (1 << n); ++i)
{
ll sum = 0, k = 0;
for (int j = 0; j < n; ++j)
if (i >> j & 1)
sum += f[j] + 1, ++k;
res = (res + (k & 1 ? -1 : 1) * Lucas(s + n - 1 - sum, n - 1)) % mod;
}
cout << (res + mod) % mod << endl;
return 0;
}

最后

以上就是愤怒凉面为你收集整理的Codeforces 451E 容斥原理的全部内容,希望文章能够帮你解决Codeforces 451E 容斥原理所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部