『容斥原理和多重集组合数』
<更新提示>
<第一次更新>
<正文>
容斥原理#
设S1,S2,...,Sn为n个有限集合,|S|代表集合S的大小,则有
多重集组合数#
容斥原理的一个重要运用就是计算多重集组合数。
设S={n1∗a1,n2∗a2,...,nk∗ak}是由n1个a1,n2个a2,...,nk个ak组成的多重集。设n=∑ki=1nk,则对于任意r≤n,从S中取出r个元素组成的多重集方案数为
证明:
不考虑ni的限制,从S中任选r个元素,相当于从多重集S={∞∗a1,∞∗a2,...,∞∗ak}取出r个元素,则由组合数的知识可得方案数为Ck−1k+r−1。
设Si为包含至少ni+1个元素ai的多重集,那么我们先从S中选ni+1个ai,然后任选剩下r−ni−1个元素,其方案数为Ck−1k+r−ni−2。
那么先从S中先选ni+1个ai,nj+1个aj,再任选剩下r−ni−nj−2个元素,就可以得到Si∩Sj的方案数为Ck−1k+r−ni−nj−3。
依次类推,用容斥原理可得至少有一种元素超过限制的方案数为:
那么合法的方案数就是
Devu and Flowers#
Description#
Devu wants to decorate his garden with flowers. He has purchased nn boxes, where the ii -th box contains f_{i}fi flowers. All flowers in a single box are of the same color (hence they are indistinguishable). Also, no two boxes have flowers of the same color.
Now Devu wants to select exactly ss flowers from the boxes to decorate his garden. Devu would like to know, in how many different ways can he select the flowers from each box? Since this number may be very large, he asks you to find the number modulo (10^{9}+7)(109+7) .
Devu considers two ways different if there is at least one box from which different number of flowers are selected in these two ways.
Input Format#
The first line of input contains two space-separated integers nn and ss ( 1<=n<=201<=n<=20 , 0<=s<=10^{14}0<=s<=1014 ).
The second line contains nn space-separated integers f_{1},f_{2},...\ f_{n}f1,f2,... fn ( 0<=f_{i}<=10^{12}0<=fi<=1012 ).
Output Format#
Output a single integer — the number of ways in which Devu can select the flowers modulo (10^{9}+7)(109+7) .
Sample Input#
3 5
1 3 2
Sample Output#
3
解析#
多重集组合数模板题,直接利用容斥原理的结论即可。
在实现代码时,可以枚举x=1到2n−1,若该数字在二进制表示下第p1,p2,...,pk位为1,则表示上式中的(−1)kCk−1k+r−np1−np2−...−npk−(p+1)这一项,由于n的范围很大,m的范围很小,所以直接计算组合数,利用费马小定理乘上逆元即可。
Code:
#include <bits/stdc++.h>
using namespace std;
const long long N=22,Mod=1e9+7;
long long n,s,a[N],inv[N],ans;
inline void input(void)
{
scanf("%lld%lld",&n,&s);
for (int i=1;i<=n;i++)
scanf("%lld",&a[i]);
}
inline long long power(long long a,long long b)
{
long long res = 1;
while (b)
{
if (1&b)res = res * a % Mod;
b >>= 1;
a = a * a % Mod;
}
return res;
}
inline void init(void)
{
for (int i=1;i<=20;i++)
inv[i] = power(i,Mod-2);
}
inline long long C(long long u,long long d)
{
if ( u>d || u<0 || d<0 )return 0LL;
d %= Mod;
long long res=1;
for (int i=0;i<u;i++)
res = res * (d-i) % Mod;
for (int i=1;i<=u;i++)
res = res * inv[i] % Mod;
return res;
}
inline long long Lucas(long long u,long long d)
{
if (u<=Mod&&d<=Mod)return C(u,d) % Mod;
else return Lucas(u/Mod,d/Mod) * C(u%Mod,d%Mod) % Mod;
}
inline void solve(void)
{
for (int i=0;i< 1<<n ;i++)
{
long long d = n + s , cnt = 0;
for (int j=0;j<n;j++)
if ( i >> j & 1 )
cnt++ , d -= a[j+1];
d -= cnt+1;
if ( 1 & cnt )
ans = (ans - Lucas(n-1,d)) % Mod;
else ans = (ans + Lucas(n-1,d)) % Mod;
}
}
int main(void)
{
input();
init();
solve();
printf("%lld\n",(ans+Mod)%Mod);
return 0;
}
<后记>
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 《HelloGitHub》第 108 期
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
· MQ 如何保证数据一致性?
· Windows桌面应用自动更新解决方案SharpUpdater5发布