• 0926考试T3 容斥原理+组合数学


    0926考试T3

    ​ 题目大意:

    (n le 10 ^ 5, 10 ^ 5 le m le 10^9, y_i le 50, 0 le S le min(M,sum y_i))

    ​ 容斥原理 + 组合数学。

    ​ 一开始看到这题很蒙啊,根本不知道从哪去想,于是就写了个爆搜。

    ​ 我就直接粘题解吧,稍微解释一下。

    ​ 把集合根据大小分类那个式子:当(i = 0)时,(f(H))不就是所有(x >= 0)的时候吗,那相当于没有任何限制,是所有情况。当(i = 1)时,(f(H))是一个数一定不满足的情况,给他减去,然后以此类推,两个数的时候再加上。

    (f(H))的取值咋解释呢?你可以理解为(S)个1,要把它分为(n)个数,这(n)个数可以为0,所以在给它加(n)个1。有(S +n)个1,就有(s + n - 1)个间隙,(n - 1)个板将他们分成(n)个数。这(n)个数有属于(H)的有不属于的。对于那些属于(H)的,它需要满足(x_i > y_i),所以这(S + n)个1还要再减去(sum _{i subseteq H} (y_i + 1))个1。加一是因为(y_i + 1)一定可以满足(x_i > y_i)的条件。

    ​ 底下那个化简:(m)(c+1)的个数,(i)为集合元素个数,枚举(j <= m, j <= i)(-j-i(c+1))就是有集合中有(i)个数,给其中的(j)个数(+1)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 6e6 + 5, mod = 998244353;
    int n, s, m, c, ans, sum;
    int y[N], fac[N], inv[N];
    
    void make_pre() {
        fac[0] = fac[1] = inv[0] = inv[1] = 1;
        for(int i = 2;i <= N - 5; i++) fac[i] = 1ll * fac[i - 1] * i % mod;
        for(int i = 2;i <= N - 5; i++) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
        for(int i = 2;i <= N - 5; i++) inv[i] = 1ll * inv[i - 1] * inv[i] % mod;
    }
    
    int C(int x, int y) {
        if(x < y) return 0;
        return 1ll * fac[x] * inv[y] % mod * inv[x - y] % mod; 
    }
    
    int calc(int s, int m) {
        int res = 0;
        for(int i = 0;i <= n; i++) {
            int tmp = 0;
            for(int j = 0;j <= m && j <= i; j++) {
                (tmp += 1ll * C(s - j - i * (c + 1) + n - 1, n - 1) * 
                 C(m, j) % mod * C(n - m, i - j) % mod) %= mod;
            }
            if(i & 1) res = (res - tmp + mod) % mod;
            else res = (res + tmp) % mod;
        }
        return res;
    }
    
    int main() {
    
        n = read(); s = read(); m = read();
        make_pre(); c = 51;
        for(int i = 1;i <= n; i++) y[i] = read(), sum += y[i], c = min(c, y[i]);
        
        for(int i = s;i <= sum; i += m) 
            ans = (ans + calc(i, sum - c * n)) % mod;
        
        printf("%lld", ans);
    
        
        fclose(stdin); fclose(stdout);
        return 0;
    }   
    
  • 相关阅读:
    PTA甲级—树
    PTA甲级—链表
    PTA刷题记录
    PTA甲级—数学
    PTA甲级—常用技巧与算法
    PAT甲级—暴力搜索
    Qt连连看(三)非核心功能实现
    常见数据类型取值范围与10的数量级对照
    PTA甲级—STL使用
    Qt连连看(二)界面制作
  • 原文地址:https://www.cnblogs.com/czhui666/p/13737574.html
Copyright © 2020-2023  润新知