Devu和鲜花(容斥原理)
题意:Devu 有 个盒子,第 个盒子中有 枝花。同一个盒子内的花颜色相同,不同盒子内的花颜色不同。Devu 要从这些盒子中选出 枝花组成一束,求共有多少种方案。若两束花每种颜色的花的数量都相同,则认为这两束花是相同的方案。结果需对 取模之后方可输出。
- 先不考虑带限制条件的情况(每个盒子中的花数量为无限),即从个盒子中每个选择枝花,最后组成枝花,很明显的一个球盒问题,且允许为空答案即为
- 考虑带上限制,我们反着思考其补集,答案即为不带限制的答案减去至少有一个盒子取出的花的数量不满足限制
- 分别代表第个盒子中取出的花的枝数不符合题目要求,此时要先拿出枝花先分配出去,剩下的部分就可看做没有限制的球盒模型了,方案数即为。由此可知答案即为所求
- 后面的集合并式很明显可以用容斥原理拆开解决,从枚举集合的状态第位为代表选择的集合求交,为则代表不选,符合由选择的集合个数决定
主要就是面对这种求方案正求不好求的时候,可以考虑容斥原理,变换一下问题的形式,而操作容斥原理,即为枚举集合的种状态。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
int ksm(int a,int b) {
int res = 1;
while(b) {
if(b & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
int down;
int C(ll n,ll m) {
if(n < m) return 0;
int up = 1;
for(ll i = n;i > n - m;i --) {
up = 1ll * up * i % mod;
}
// cout << up << ' ' << down << '\n';
return 1ll * up * down % mod;
}
int main() {
ll n,m; cin >> n >> m;
vector<ll>A(n + 1);
for(int i = 1;i <= n;i ++) {
cin >> A[i];
}
down = 1;
for(int i = 1;i < n;i ++) {
down = 1ll * down * i % mod;
}
down = ksm(down,mod - 2);
int ans = 0;
for(int S = 0;S < 1 << n;S ++) {//容斥原理 枚举2^n这种情况
ll a = n + m - 1,b = n - 1;
int count = 0;
for(int j = 0;j < n;j ++) {
if(S >> j & 1) {
count ++;
a -= A[j + 1] + 1;
}
}
int sign = count & 1 ? -1 : 1;
// cout << a << ' ' << b << ' ' << sign << '\n';
ans = (ans + C(a,b) * sign) % mod;
}
ans = (ans + mod) % mod;
cout << ans << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2021-05-31 NWERC2020 A - Atomic Energy (背包 + 思维)