• [BZOJ3027][CEOI2004] Sweets


    题目描述

    (John)得到了(n)罐糖果。不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的)。第(i)个糖果罐里有(m_{i})个糖果。(John) 决定吃掉一些糖果,他想吃掉至少(a)个糖果,但不超过(b)个。问题是 (John)无法确定吃多少个糖果和每种糖果各吃几个。有多少种方法可以做这件事呢?

    解题思路

    生成函数题,考虑对于第(i)堆吃(j)个糖果的方案并写成封闭模式为

    [F_i(x)=sum_{j=0}^{m_i}x^j=frac{1-x^{m_i+1}}{1-x} ]

    那么对于吃(i)个的方案数为

    [G(x)=prod_{i=1}^n F_i(x)=(1-x)^{-n}prod_{i=1}^n(1-x^{m_i+1}) ]

    对于((1-x)^{-n})我们使用牛顿广义二项式展开可得(egin{aligned}(1-x)^{-n}=sum_{k=0}^{infty}dbinom{-n}{k}(-x)^k=sum_{k=0}^{infty}(-1)^kdbinom{n+k-1}{k}(-x)^k=sum_{k=0}^{infty}dbinom{n+k-1}{k}x^kend{aligned})

    对于后面的柿子我们直接暴搜,怎么暴力怎么来就可以,对于前面的(egin{aligned}sum_{k=0}^{infty}dbinom{n+k-1}{k}x^kend{aligned}),我们考虑对答案的贡献,对于答案是(x^a)~(x^b)对应的系数,则设(prod_{i=1}^n(1-x^{m_i+1}))枚举到了(x^k),则为(egin{aligned}sum_{i=a-k}^{b-k}dbinom{n+i-1}{i}end{aligned}),展开后对其用加法公式(dbinom{n}{m}=dbinom{n-1}{m}+dbinom{n-1}{m-1})进行化简可得为(dbinom{n+b-k}{b-k}-dbinom{n+a-k-1}{a-k-1}),然后就可以做了,总体时间复杂度为(O(2^n))

    细节注意

    模数不是质数,组合数用定义进行计算

    (Code)

    #include<bits/stdc++.h>
        
    #define LL long long
        
    #define _ 0
        
    using namespace std;
        
    /*Grievous Lady*/
        
    template <typename _n_> void mian(_n_ & _x_){
        _x_ = 0;int _m_ = 1;char buf_ = getchar();
        while(buf_ < '0' || buf_ > '9'){if(buf_ == '-')_m_ =- 1;buf_ = getchar();}
        do{_x_ = _x_ * 10 + buf_ - '0';buf_ = getchar();}while(buf_ >= '0' && buf_ <= '9');_x_ *= _m_;
    }
        
    const int kato = 20;
    
    LL fac = 1 , ans , n , a , b , m[kato];
    
    #define mod 2004
    
    inline int c(int a , int b){
        if(a < b) return 0;
        LL res = 1 , tmp = fac * mod;
        for(int i = a - b + 1;i <= a;i ++){
            res = res * i % tmp;
        }
        return (res / fac) % mod;
    }
    
    void dfs(int x , int opt , int t){
        if(x == n + 1){
            ans = (ans + opt * (c(n + b - t , n) - c(n + a - t - 1 , n))) % mod;
            return;
        }
        dfs(x + 1 , opt , t) , dfs(x + 1 , - opt , t + m[x] + 1);
    }
    
    inline int Ame_(){
        mian(n) , mian(a) , mian(b);
        for(int i = 1;i <= n;i ++){
            mian(m[i]);
            fac = fac * i;
        }
        dfs(1 , 1 , 0);
        if(ans < 0) ans += mod;
        printf("%lld
    " , ans);
        return ~~(0^_^0);
    }
        
    int Ame__ = Ame_();
        
    int main(){;}
    
    /*
    2 1 3
    3
    5
    */
    

    -----(mathcal{Ame\_\_})

  • 相关阅读:
    http状态码
    闭包
    节流和防抖
    继承方式
    array和object对比
    排序算法
    算法题
    汇编 asm 笔记
    FFMPEG 内部 YUV444P016 -> P010
    FFMPEG 内部 YUV444p16LE-> P016LE
  • 原文地址:https://www.cnblogs.com/Ame-sora/p/13603968.html
Copyright © 2020-2023  润新知