经典容斥
题意就不说了.
解法
理想情况
理想每一组中可以取无限朵花,那么我们就需要达到$x_1+x_2+x_3+……+x_n=M$。
此时$x_i>=0$,那么令$y_i=x_i+1$,则$y_1+y_2+y_3+……+y_n=M+N$。
因为$y_i>=1$,所以可以用隔板法,在$M+N-1$个空隙中插入$N-1$个板,答案为$C_{M+N-1}^{N-1}$。
实际
在实际中有$x_1<=A_1,x_2<=A_2,x_3<=A_3……x_n<=A_n$等条件,此时就需要同时满足这N个条件。
那么正难则反,考虑求补集,也就是至少不满足其中一个条件的方案。就可以用总方案减去这些方案就可以得出答案。
设不满足$i$的方案为$s_i$,
那么答案就是$C_{M+N-1}^{N-1}-|s_1\bigcup s_2\bigcup s_3……\bigcup s_n|$。
将其展开就是:
$C_{M+N-1}^{N-1}-|s_1|-|s_2|-……|s_3|+|s_1\bigcap s_2|+……-|s_1\bigcap s_2\bigcap s_3|-……$。
就是一个容斥原理的展开。
考虑$s_i$怎么求。以$s_1$举例,假如要求$s_1$,就代表我们必须从第一组里取出至少$A_1+1$朵花,那么此时还剩$M-(A_1+1)$朵花。剩下的就是隔板,
那么此时方案就是$C_{M+N-1-(A_1+1)}^{N-1}$。
那么$|s_1\bigcap s_2|$同上,方案就是$C_{M+N-1-(A_1+1)-(A_2+1)}^{N-1}$。
整理一下,就得到 $res=C_{M+N-1}^{N-1}-\sum\limits_{i=1} C_{M+N-1-(A_i+1)}^{N-1}+\sum\limits_{i<j} C_{M+N-1-(A_i+1)-(A_j+1)}^{N-1}-……$。
总所周知,容斥复杂度$O(2^n)$,那么可以从$0枚举到2^{n-1}$。
然后把每一个条件看成一个二进制位,如果是$1$或$0$就代表遵守或不遵守这个条件,奇数个就减,偶数个就加。
那么怎么去算组合数,可以发现虽然$M$非常大,但是我们的$N$很小,所以只需按着定义去算,大概是$N$的复杂度。所以总的复杂度就是$O(2^N*N)$。
参考代码
/*
容斥+组合数计算.
*/
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long ll;
const int N=25;
ll n,m;
int res;
ll a[N];
int down=1;
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 C(ll a,ll b) {
if(a<b) return 0;
int up=1;
for(ll i=a; i>a-b; --i) up=i%mod*up%mod;
return 1ll*up*down%mod;
}
int main() {
scanf("%lld%lld",&n,&m);
for(int i=0; i<n; ++i) scanf("%lld",&a[i]);
for(int i=1; i<=n-1; ++i) down=1ll*i*down%mod;
down=ksm(down,mod-2);
for(int i=0; i<(1<<n); ++i) {
ll d=m+n-1,up=n-1;
int sign=1;
for(int j=0; j<n; ++j) {
if((i>>j)&1) {
sign*=-1;
d-=a[j]+1;
}
}
res=(res+C(d,up)*sign)%mod;
}
printf("%d\n",(res+mod)%mod);
return 0;
}
佬,时间复杂度那儿,应该是从0枚举到 $2^n−1$吧
就是 $2^n-1$
请问对于$S_1$而言,如果首先拿出$A_1 + 1$朵花,在隔板时至少还会拿出1多花,这样最终结果不就变成了在第一堆花中至少拿出$A_1 + 2$朵花吗?可是我们想求的不应该是在第一堆花中至少拿出$A_1 + 1$朵花的方案数吗?这样想是哪里错了呀
同问
因为在处理的时候为了使用隔板法,已经将每个数都加1,变成大于1的数,所以这里的先拿出$a_1$ + 2 朵花其实是至少拿 $a_i$ + 1 朵花,,可以参考洛谷题解 洛谷题解
困惑好长时间了,Mark!!
同问
因为这里的隔板法一个表示零个
隔板法求的时候是假设每个x从0开始记得,后面的y是替换了一下,假设情况你再理解理解
写得很清楚哈
这个复杂度为什么我感觉会超时呢
N不大,算下来也就千万级别的
tql
大佬,这道题如果m很小的话是不是可以拿多重背包来做
可以试一下,好久没看过了,QAQ
好的呢
讲的很好,大佬可以多写点博客hh
#Orz