洛谷 U140604 送花

洛谷 U140604 送花

洛谷传送门

题目背景

SeawaySeawa**y的老婆大人RoseRos**e要过生日啦!为了给老婆大人庆生,SeawaySeawa**y正打算给RoseRos**e送上一束盛开着的鲜花......

题目描述

认真起来的SeawaySeawa**y为了庄重地庆贺这个生日,大手一挥,买下了NN个花箱。在编号为ii的箱子里,有f[i]f[i]朵相同颜色的花。每个箱子里面的花的颜色两两不同。SeawaySeawa**y要从这些箱子里挑选SS朵花扎成花束,送给老婆大人。SeawaySeawa**y当然可以随意挑选SS朵花。但因为他一共买下了这么多花,如果只组一种花束未免浪费。但RoseRos**e也不喜欢一次性收到太多的花束。所以SeawaySeawa**y便开始思考:对于他买下的这些花,他有多少种挑选方式,使之能够组成SS朵花的花束?SeawaySeawa**y规定,两种挑选方式不同,当且仅当存在同一种颜色的花数量不同。由于答案可能很大,请输出答案对10^9+7109+7取模的结果。

输入格式

从文件blossom.inblossom.i**n中读入数据。

第一行两个整数N,SN,S,意义如题目描述所示。

第二行NN个整数,第ii个整数表示第ii个花箱里的花的数量f[i]f[i]。

输出格式

输出到文件blossom.outblossom.out中。

输出一行一个整数ansans,表示总挑选方案数量按要求取模后的结果。


题解:

题解:

排列组合这个地方的确比较难理解,来给大家用大白话讲一下。

多重集排列组合。

不妨反着来:对于有\(N\)种元素的多重集\(S\),选\(K\)个元素,注意是个不是种,的可行方案数。可以变成:现在有\(N\)个篮子,把\(K\)个元素扔进这些篮子里的方案数。

注意,这种是特殊情况,也就是说,每种元素无限多个可供挑选。

这样的话,用隔板法解决问题。

容易得出,答案也就是\(C_{N+K-1}^{N-1}\)

解释一下,现在有\(K\)个元素,分成\(N\)堆,也就是要往里插入\(N-1\)块板。按理讲应该是\(C_{K+1}^{N-1}\),但是因为允许有空集,也就是不插,那么就相当于每块板子插进去之后又产生了新元素,所以是这个答案。

那么,根据多重集的限制,现在每种元素有一个数量上限,怎么办呢?

很简单,采用容斥原理。关于容斥原理,请见:

浅谈容斥原理

上限是“至多放\(f[i]\)个”,那么如果我往这个里面放\(f[i]+1\)个,是不是就不合法了?

把不合法的减去即可。

因为这道题N只有20,所以考虑状压,表示当前这个集合超没超。

最后根据容斥,如果当前状态1的个数是奇数,就要减去,是偶数,就要加上。

代码:

#include<cstdio>
#define ll long long
using namespace std;
const int maxn=25;
const int mod=1e9+7;
int n;
ll s;
ll f[maxn],inv[maxn];
ll calc(ll n,ll m)
{
	if(n<0||m<0||n<m)
		return 0;
	n%=mod;
	if(n==0||m==0)
		return 1;
	ll ret=1;
	for(int i=0;i<m;i++)
		ret=(ret*(n-i))%mod;
	for(int i=1;i<=m;i++)
		ret=(ret*inv[i])%mod;
	return ret;
}//n中选m的组合数
ll qpow(ll a,ll b)
{
	ll ret=1;
	while(b)
	{
		if(b&1)
			ret=(ret*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ret;
}
int main()
{
	scanf("%d%lld",&n,&s);
	for(int i=1;i<=n;i++)
		scanf("%lld",&f[i]);
	for(int i=1;i<=20;i++)
		inv[i]=qpow(i,mod-2);
	ll ans=calc(n+s-1,n-1)%mod;
	for(int i=1;i<(1<<n);i++)
	{
		ll tot=n+s;
		int p=0;
		for(int j=0;j<n;j++)
			if(i>>j&1)
			{
				p++;
				tot-=(f[j+1]+1);
			}
		tot--;
		if(p&1)
			ans=(ans-calc(tot,n-1))%mod;
		else
			ans=(ans+calc(tot,n-1))%mod;
	}
	printf("%lld\n",(ans+mod)%mod);
	return 0;
}
posted @ 2020-11-17 19:37  Seaway-Fu  阅读(67)  评论(0编辑  收藏  举报