zoukankan      html  css  js  c++  java
  • 2020Nowcode多校 Round5 C. Easy

    C. Easy

    构造两个序列分别要满足 (sum_{i=1}^{k} a_{i} = N) (sum_{i=1}^{k} b_{i} = M)
    一种方案能贡献(prod_{i=1}^{k} min(a_{i}, b_{i})) 的分数 求所有方案分数的和

    生成函数

    对于一个序列 (a_{0},a_{1},a_{2})···
    定义它的生成函数为 (G(x) = a_{0} + a_{1}x + a_{2}x^{2})···
    生成函数有指数和系数两维信息 所以用来解决计数问题非常强大 因此生成函数的构造是比较关键的

    在本题中一个序列不同的方案数 其实就是就把N划分成K个数的方案数
    对于每一个数我们可以用一个生成函数(G(x) = x+x^{2}+x^{3})···来表示
    它的意义是 每一项其实就是一种操作 比如(x^{2})表示让这一位为2(指数)的方案数为1(系数)
    那么把N划分成K个数的方案数就是 ((G(x))^{k} = (x + x^{2}+x^{3}···)^{k})(x^{N})的系数

    如果想维护出一个序列所有方案分数的和 我们可以巧妙的构造 ((G(x))^{k} = (x + 2x^{2}+3x^{3}···)^{k})
    它的意义是 比如(2x^{2})表示让这一位为2(指数)能让这一种方案的分数(*2)(系数)

    min的生成函数

    容易想到 对于两个数我们可以构造一个生成函数(G(x,y) = (x + x^{2} + x^{3}···)(y+y^{2}+y^{3}···))(x^{i}y^{j})来表示第一个数为i 第二个数为j
    我们只用了它的指数 显然还有系数可以用来维护信息 能不能用一种构造使得它的系数为(min(i,j))

    先上结论 我们可以在(G(x,y))后乘上一个(1+xy+x^{2}y^{2})···
    理解一下 假设(i<j) 它实际上是提供了一个映射 让原来的(x^{i}y^{j},x^{i-1}y^{j-1},x^{i-2}y^{j-2}···x^{1}y^{j-i+1})一共(i)项都为(x^{i}y^{j})的系数做了一次贡献
    所以在这个多项式里(x^{i}y^{j})的系数恰好为(min(i,j))

    题解

    综上所述 答案为(G(x,y) = (x + x^{2} + x^{3}···)^{k}(y+y^{2}+y^{3}···)^{k}(1+xy+x^{2}y^{2}···)^{k})这个多项式中(x^{N}y^{M})的系数
    我们可以枚举最后一项中(x^{i}y^{i})的指数 就可以得到第一个项中(x)的指数为(N-i) 第二项(y)的指数为(M-i)
    然后分别计算它们的系数 最后一项是把i个物品分为K个可以为空的集合 前两项分别是把(N-i)(M-i)个物品分为K个非空集合
    (ans = sum_{0}^{min(N-K,M-K)} inom{N-i-1}{K-1} inom{M-i-1}{K-1} inom{i+K-1}{i})

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    #include <queue>
    #include <map>
    using namespace std;
    typedef long long ll;
    const int mod = 998244353;
    const int MAXN = 1000005;
    int n, m, k;
    int fac[MAXN];
    int ny[MAXN];
    int inv[MAXN];
    
    int C(int x, int y) {
        if(x < y || y < 0 || x < 0) return 0;
        return 1LL * fac[x] * inv[x - y] % mod * inv[y] % mod;
    }
    
    int main() {
        fac[0] = ny[0] = inv[0] = 1; ny[1] = 1;
        for(int i = 1; i <= 1000000; i++) {
            fac[i] = 1LL * i * fac[i - 1] % mod;
            if(i > 1) ny[i] = 1LL * ny[mod % i] * (mod - mod / i) % mod;
            inv[i] = 1LL * ny[i] * inv[i - 1] % mod;
        }
    
        int T;
        cin>>T;
        while(T--) {
            scanf("%d%d%d", &n, &m, &k);
    
            int ans = 0;
            for(int i = 0; i <= min(n, m) - k; i++) {
                int tmp = 1LL * C(k + i - 1, i) * C(n - i - 1, k - 1) % mod * C(m - i - 1, k - 1) % mod;
                ans = (ans + tmp) % mod;
            }
            printf("%d
    ", ans);
        }
    
        return 0;
    }
    
  • 相关阅读:
    等待队列设备[置顶] Linux设备驱动,等待队列
    宠物功能[置顶] QQ宠物保姆
    选中拖动Unity3D系列教程–使用免费工具在Unity3D中开发2D游戏 第二节(下)
    序列化对象java中为什么要实现序列化,什么时候实现序列化?
    函数表达式[置顶] 母函数详解
    文件问题cocos2dx&cocosbuilder折腾记
    模块functionJavaScript学习笔记(二十五) 沙箱模式
    nullnullflume ng配置拓扑图
    对象序列化对象的序列化和反序列化
    扩展编程PHP自学之路PHP数据库编程
  • 原文地址:https://www.cnblogs.com/lwqq3/p/13383059.html
Copyright © 2011-2022 走看看