214. Devu和鲜花

题目链接

214. Devu和鲜花

Devu 有 \(N\) 个盒子,第 \(i\) 个盒子中有 \(A\_i\) 枝花。

同一个盒子内的花颜色相同,不同盒子内的花颜色不同。

Devu 要从这些盒子中选出 \(M\) 枝花组成一束,求共有多少种方案。

若两束花每种颜色的花的数量都相同,则认为这两束花是相同的方案。

结果需对 \(10^9+7\) 取模之后方可输出。

输入格式

第一行包含两个整数 \(N\)\(M\)

第二行包含 \(N\) 个空格隔开的整数,表示 \(A_1,A_2,…,A_N\)

输出格式

输出一个整数,表示方案数量对 \(10^9+7\) 取模后的结果。

数据范围

\(1 \le N \le 20\),
\(0 \le M \le 10^{14}\),
\(0 \le A_i \le 10^{12}\)

输入样例:

3 5
1 3 2

输出样例:

3

解题思路

容斥原理

考虑鲜花个数不限的情况,即满足 \(x_1+x_2+\dots +x_n=m\),其中 \(x_1,x_2,\dots ,x_n \geq 0\),设 \(y_i=x_i+1\),则 \(y_1+y_2+\dots +y_n=m+n\),其中 \(y_1,y_2,\dots ,y_n \geq 1\),即转化为在 \(n+m-1\) 中插 \(n-1\) 个板子的隔板问题,方案数为 \(C_{n+m-1}^{n-1}\),然后要求 \(s_1+s_2+\dots+s_n=m\),其中 \(s_i\) 表示满足 \(x_i\leq a_i\) 的条件,由容斥定理有 \(s_1\bigcap s_2\bigcap \dots\bigcap s_n=C_{n+m-1}^{n-1}- \sim (s_1\bigcap s_2\bigcap \dots\bigcap s_n)\),其中 \(\sim (s_1\bigcap s_2\bigcap \dots\bigcap s_n)\) 表示至少有一个 \(s_i\) 不满足条件,当只有 \(s_1\) 不满足条件时,即 \(x_1\) 至少选了 \(a_1+1\) 个数,选走 \(a_1+1\) 个数后,还剩 \(m-(a_1+1)\) 个数,此时又可通过隔板问题得方案数 \(C_{n+m-1-(a_1+1)}^{n-1}\),其他单个不满足条件同理,同时对于多个单个条件同时满足时也需要考虑容斥,最后答案为 \(C_{n+m-1}^{n-1}-\sum_{i=0}^{i=n-1}C_{n+m-1-(a_i+1)}^{n-1}+\sum_{i=0,i\leq j}^{j=n-1}C_{n+m-1-(a_i+1)-(a_j+1)}^{n-1}-\dots\)

  • 时间复杂度:\((n\times 2^n)\)

代码

// Problem: Devu和鲜花
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/216/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
// #define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=20,mod=1e9+7;
int n,res,t=1;
LL a[N],m;
int ksm(int a,int b,int p)
{
	int res=1%p;
	while(b)
	{
		if(b&1)res=1ll*res*a%p;
		a=1ll*a*a%p;
		b>>=1;
	}
	return res;
}
int C(LL a)
{
	if(a<n-1)return 0;
	int res=1;
	for(LL i=a;i>=a-n+2;i--)res=i%mod*res%mod;
	return 1ll*res*t%mod;	
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<n;i++)t=1ll*t*i%mod;
    t=ksm(t,mod-2,mod);
    for(int i=0;i<n;i++)cin>>a[i];
    for(int i=0;i<(1<<n);i++)
    {
    	LL b=n+m-1,sign=1;
    	for(int j=0;j<n;j++)
    		if(i>>j&1)b-=a[j]+1,sign*=-1;
    	res=(res+C(b)*sign)%mod;
    }
    cout<<(res+mod)%mod;
    return 0;
}
posted @ 2022-06-28 12:03  zyy2001  阅读(34)  评论(0编辑  收藏  举报