CF451E Devu and Flowers

CF

luogu

De javu 和开花

咕了半个月没更博了(捂脸)

这题如果值域小显然可以背包,但是这题是(n)小值域大,(20)可以让人想到状压.分析一下又发现可以容斥,枚举哪些物品超过个数限制,设枚举集合为(S),然后每个物品都要用(a_i+1)个,那么这个集合的贡献为((-1)^{|S|}inom{s-(sum a_i+1)+n-1}{n-1})

// luogu-judger-enable-o2
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db long double

using namespace std;
const int N=30,M=(1<<20)+10,mod=1e9+7;
LL rd()
{
    LL x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int n,nn,fac[N],iac[N],l2[M],fh[M];
LL s,a[N],b[M];
int fpow(int a,int b){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;} return an;}
int inv(int a){return fpow(a,mod-2);}
int C(LL n,int m)
{
    if(m<0||n<m) return 0;
    LL xx=1;
    for(int i=0;i<m;++i) xx=1ll*xx*(n%mod-i+mod)%mod;
    return 1ll*xx*iac[m]%mod;
}
int cal(LL n,int m){return C(n+m-1,m-1);}

int main()
{
    n=rd(),s=rd();
    for(int i=1;i<=n;++i) a[i]=rd();
    fac[0]=1;
    for(int i=1;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod;
    iac[n]=inv(fac[n]);
    for(int i=n;i;--i) iac[i-1]=1ll*iac[i]*i%mod;
    nn=1<<n;
    for(int i=1;i<=n;++i) l2[1<<(i-1)]=i;
    fh[0]=1;
    for(int i=1;i<nn;++i) fh[i]=-fh[i^(i&(-i))],b[i]=b[i^(i&(-i))]+a[l2[i&(-i)]]+1;
    int ans=0;
    for(int i=0;i<nn;++i)
    {
        int dt=cal(s-b[i],n);
        ans=(ans+(fh[i]==1?dt:mod-dt))%mod;
    }
    printf("%d
",ans);
    /*qwq*/
    return 0;
}
原文地址:https://www.cnblogs.com/smyjr/p/10991773.html