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;
}
posted @ 2021-06-12 01:05  acmloser  阅读(41)  评论(0编辑  收藏  举报