• 《HDU


    区间[0,n - 1]选定m个数使得他们的和 = k.(可以重复选择)
    考虑隔板法:
    将k看成k个1.那么就是在这k个数里面插入m - 1个板子的方案数。
    即C(k - 1,m - 1)
    为什么k - 1,因为两边不能插,为什么两边不能插了可能导致不是m个数。
    然后我们这样插显然不存在值为0的情况,但是选择的值又可以为0。
    所以我们采取扩下限的思路。
    我们把选定的区间变成[1,n],让[1,n]来代表[0,n - 1]。
    也就是说我们插入隔板出来的值是1,就相当与原来区间的0.
    那么也可以发现,我们这样的话每个值都固定加了1,所以我们的k也需要加m个1。
    即题意转化为,选[1,n] = k + m。
    此时:我们考虑选的值可以 > n,即没有限制的情况。
    即C(k + m - 1,m - 1)。
    但是这里有限制。所以我们要考虑容斥思想去存在值 >= n + 1的情况。
    定义f[i] = 有i个数超过n的方案数量。
    我们考虑怎么计算这个方案数。
    假设我们现在从m份中拿出了1个n,然后这k + m - 1 - n排成非空的m份即C(k + m - 1 - n,m - 1)。
    然后我们再随机把这个n加入到某一份中即C(m,1)那么此时加入的那一份必定 > n。
    两份也同理。
    所以f[i] = C(m,i) * C(k + m - 1 - i * n,m - 1).
    但是这里可能存在减去其他f[i]的情况。
    所以要用到容斥思想:
    对于N个物品都至多N个 > n的组合方案 = (1个球 > n的方案数量) - (2个球 > n的方案数量) + (3个球..) - (4个球..)
    可以发现是奇加偶减。但是因为我们是要去减去这个方案数。
    所以变成奇减偶加。
    所以最后为:$ans = inom{m - 1}{k + m - 1} * sum_{1}^{m} inom{i}{m} * inom{m - 1}{k + m - 1 - i * n} * (-1)_{}^{i}$
    这里需要预处理阶乘的逆元,不然时间复杂度不够。
    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 2e5 + 5;
    const int M = 1e5 + 5;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline LL read(){
            LL x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    /*
    区间[0,n - 1]选定m个数使得他们的和 = k.
    考虑隔板法:
    将k看成k个1.那么就是在这k个数里面插入m - 1个板子的方案数。
    即C(k - 1,m - 1)
    为什么k - 1,因为两边不能插,为什么两边不能插了可能导致不是m个数。
    然后我们这样插显然不存在值为0的情况,但是选择的值又可以为0。
    所以我们采取扩下限的思路。
    我们把选定的区间变成[1,n],让[1,n]来代表[0,n - 1]。
    也就是说我们插入隔板出来的值是1,就相当与原来区间的0.
    那么也可以发现,我们这样的话每个值都固定加了1,所以我们的k也需要加m个1。
    即题意转化为,选[1,n] = k + m。
    此时:我们考虑选的值可以 > n,即没有限制的情况。
    即C(k + m - 1,m - 1)。
    但是这里有限制。所以我们要考虑容斥思想去存在值 >= n + 1的情况。
    定义f[i] = 有i个数超过n的方案数量。
    我们考虑怎么计算这个方案数。
    假设我们现在从m份中拿出了1个n,然后这k + m - 1 - n排成非空的m份即C(k + m - 1 - n,m - 1)。
    然后我们再随机把这个n加入到某一份中即C(m,1)那么此时加入的那一份必定 > n。
    两份也同理。
    所以f[i] = C(m,i) * C(k + m - 1 - i * n,m - 1).
    但是这里可能存在减去其他f[i]的情况。
    所以要用到容斥思想:
    对于N个物品都至多N个 > n的组合方案 = (1个球 > n的方案数量) - (2个球 > n的方案数量) + (3个球..) - (4个球..)
    可以发现是奇加偶减。但是因为我们是要去减去这个方案数。
    所以变成奇减偶加。
    
    
    */
    int n,m,k;
    LL f[N],inv[N];
    LL quick_mi(LL a,LL b) {
        LL re = 1;
        while(b) {
            if(b & 1) re = (re * a) % Mod;
            b >>= 1;
            a = (a * a) % Mod;
        }
        return re;
    }
    void init() {
        f[0] = 1;
        for(int i = 1;i < N;++i) f[i] = f[i - 1] * i % Mod;
        inv[N - 1] = quick_mi(f[N - 1],Mod - 2);
        for(int i = N - 2;i >= 0;--i) inv[i] = inv[i + 1] * (i + 1) % Mod;
    }
    LL C(int n,int m) {
        return f[n] * inv[m] % Mod * inv[n - m] % Mod;
    }
    int main() {
        init();
        int ca;ca = read();
        while(ca--) {
            n = read(),m = read(),k = read();
            LL ans = C(k + m - 1,m - 1);
            LL ma = 1;
            for(int i = 1;i <= m;++i) {
                ma *= -1;
                if(k + m - 1 - i * n < m - 1) break;
                ans = (ans + ma * C(m,i) % Mod * C(k + m - 1 - i * n,m - 1) % Mod) % Mod;
                ans = (ans + Mod) % Mod;
            }
            printf("%lld
    ",ans);
        }
    
        system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    常用英语1000句
    TXT EXPLORER
    窗体美化
    C++ Code_StatusBar
    C++ Code_Slider
    C++ Code_ScrollBar
    C++ Code_ImageList
    C++ Code_HotKey
    C++ Code_animateCtrl
    C++ CheckMenuItem
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/14810147.html
Copyright © 2020-2023  润新知