AcWing 214. Devu和鲜花
原题链接
考察:容斥原理
思路:
这个容斥思路应该很经典了,硬币购物也是这个思路.
如果不考虑限制,方法数就是隔板法求解:\(C_{n+m-1}^{n-1}\),但是有限制的情况下就不能这么求解.
直接求不好做,考虑求补集.至少不满足一个条件的情况,至少不满足两个条件的情况容斥即可.但是至少不满足一个的怎么求呢?可以先取\(a[i]-1\)个,然后再用隔板法求解.
Code
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 25,M=1e9+7;
int n,down=1;
LL m,a[N];
int qsm(LL a,int k,int m)
{
int res = 1;
while(k)
{
if(k&1) res = (LL)res*a%m;
a = a*a%m;
k>>=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 = (LL)up*(i%M)%M;
return (LL)up*down%M;
}
int get(LL a)
{
return (a%M+M)%M;
}
int main()
{
scanf("%d%lld",&n,&m);
for(int i=0;i<n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n-1;i++) down = (LL)down*i%M;
down = qsm(down,M-2,M);
LL res = C(m+n-1,n-1)%M;
for(int i=1;i<1<<n;i++)
{
LL sum = m+n-1; int cnt = 0;
for(int j=0;j<n;j++)
if(i>>j&1)
{
if(sum-a[j]-1<0) {cnt = -1;break;}
cnt++;
sum-=a[j]+1;
}
if(cnt==-1) continue;
if(cnt&1) res=get(res-C(sum,n-1));
else res=get(res+C(sum,n-1));
}
printf("%d\n",res);
return 0;
}