zoukankan      html  css  js  c++  java
  • 题解 CF451E 【Devu and Flowers】

    洛谷传送门

    cf传送门

    贡献一个只用到基础组合数学+容斥的做法


    假设每种花都是无穷多的。那么,方案数显然相当于 (s) 个小球,分 (k) 组,每组至少 (0) 个的方案数。

    考虑初始加入 (n) 个小球,按每组至少 (1) 个进行插空分配,之后再抽走。方案数显然为 (dbinom{s+n-1}{n-1})

    当然,这个分法显然有问题,因为每种花并不是无穷多的,这种分法可能导致一些花比限制条件更多。

    现考虑某集合 (S) ,集合中的每种花都严格多于限制条件。则对于集合中的某种花 (i) ,选择第 (i) 种花的数量 (>f_i) ,即 (geq f_i+1)

    因此,不妨设 (displaystyle f_S=sum_{iin S}(f_i+1))

    考虑集合 (S) 中每种花都严格多于限制条件的方案数,等价于先将 (s) 个小球中选出 (f_S) 个,剩余的部分分 (k) 组,每组至少 (0) 个。分配后,再将 (f_S) 个按需分配回去。因此,方案数为 (dbinom{s-f_S+n-1}{n-1})

    最后求每种花都不多于限制条件的方案数,则进行容斥:

    (0) 个超限的 (-)(1) 个超限的 (+)(2) 个超限的 $cdots $

    (displaystyle ans=sum_{S}(-1)^{|S|}dbinom{s-f_S+n-1}{n-1})

    由于 (n-1leq 19) ,直接暴力展开组合数即可,复杂度为 (O(ncdot 2^n))


    【代码】

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll MOD=1e9+7;
    inline ll fpow(ll a,ll x) { ll ans=1; for(a%=MOD;x;x>>=1,a=a*a%MOD) if(x&1) ans=ans*a%MOD; return ans; }
    inline ll inv(ll a) { return fpow(a,MOD-2); }
    //快速幂 & 逆元
    ll n,s,f[1<<20],invn;//invn 为 (n-1)! 的逆元
    inline ll C(ll n,ll m){
         if(m<0||m>n) return 0;
         ll ans=1;
         for(int i=1;i<=m;i++)
              ans=(n-i+1)%MOD*ans%MOD;
         return ans*invn%MOD;
    }
    inline ll calc(ll S){
         if(S&(S-1)) f[S]=f[S^(S&(-S))]+f[S&(-S)];
         return C(s-f[S]+n-1,n-1);
    }
    int main(){
         ios::sync_with_stdio(0);
         cin.tie(0); cout.tie(0);
         cin>>n>>s;
         invn=1;
         for(int i=1;i<=n-1;i++) invn=invn*i%MOD;
         invn=inv(invn);
         for(int i=1,s=1;i<=n;i++,s<<=1) cin>>f[s],++f[s];
         ll Ans=0;
         for(int i=0;!(i>>n);i++)
              Ans=( Ans+calc(i)*((__builtin_popcount(i>>10)+__builtin_popcount(i&1023)&1)?-1:1) )%MOD;
         //__builtin_popcount(i) 可以直接算出 i 二进制中 1 的个数,但要 i 相对较小的时候
         Ans=(Ans%MOD+MOD)%MOD;
         cout<<Ans;
         cout.flush();
         return 0;
    }
    
  • 相关阅读:
    [BZOJ1725][Usaco2006 Nov]Corn Fields牧场的安排
    [BZOJ1226][SDOI2009]学校食堂Dining
    [BZOJ2734][HNOI2012]集合选数
    [BZOJ4563][Haoi2016]放棋子
    [BZOJ4897][Thu Summer Camp2016]成绩单
    [BZOJ4896][Thu Summer Camp2016]补退选
    [POJ3155]Hard Life
    [BZOJ1486][HNOI2009]最小圈
    [BZOJ1690][Usaco2007 Dec]奶牛的旅行
    [BZOJ2144]跳跳棋
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/14389107.html
Copyright © 2011-2022 走看看