• 「CTS2019」珍珠


    「CTS2019」珍珠

    解题思路

    看了好多博客才会,问题即要求有多少种方案满足数量为奇数的变量数 (leq n-2m)。考虑容斥,令 (F(k)) 为恰好有 (n) 个变量数量为奇数的方案数,(G(k)) 为钦点了 (k) 种变量的选法且它们数量都是奇数,剩下的变量随便组合的方案数。

    那么,

    [Ans = sum_{i=0}^{min(n-2m,D)} F(i) ]

    显然 (F, G​) 之间满足以下关系:

    [G(k) =sum_{i=k}^D {ichoose k} F(i) \ F(k) =sum_{i=k}^D {ichoose k}(-1)^{i-k}G(i) ]

    第二个式子是一个经典卷积,所以只要求出 (G) 做多项式乘法就可以快速得到答案了。

    考虑钦点的变量是有标号集合的拼接,用指数型生成函数 (frac{e^{x}-e^{-x}}{2}) 的形式表示单个变量数量为奇数的选法,(e^x) 表示剩下变量随便选的选法,于是

    [G(k)=[x^n]{D choose k}(frac{e^x-e^{-x}}{2})^ke^{x(D-k)} \ =[x^n]frac{1}{2^k}{D choose k}(e^x-e^{-x})^ke^{x(D-k)} ]

    二项式展开可以得到

    [G(k)=[x^n]frac{1}{2^k}{D choose k}sum_{i=0}^k{k choose i}(-1)^ie^{x(k-2i)}e^{x(D-k)} \ =[x^n]frac{1}{2^k}{D choose k}sum_{i=0}^k{k choose i}(-1)^ie^{x(D-2i)} \ =frac{1}{2^k}{D choose k}sum_{i=0}^k{k choose i}(-1)^i(D-2i)^n ]

    发现是一个卷积的形式,也只需要一遍多项式乘法。

    code

    /*program by mangoyang*/
    #include <bits/stdc++.h>
    #define inf (0x7f7f7f7f)
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    typedef long long ll;
    using namespace std;
    template <class T>
    inline void read(T &x){
    	int ch = 0, f = 0; x = 0;
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    	for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    	if(f) x = -x;
    }
    const int N = 1 << 19, mod = 998244353, G = 3;
    int a[N], b[N], js[N], inv[N], n, m, D, ans;
    namespace poly{
        int rev[1<<22], len, lg;
        inline int Pow(int a, int b){
            int ans = 1;
            for(; b; b >>= 1, a = 1ll * a * a % mod)
                if(b & 1) ans = 1ll * ans * a % mod;
            return ans;
        }
        inline void timesinit(int lenth){
            for(len = 1, lg = 0; len <= lenth; len <<= 1, lg++);
            for(int i = 0; i < len; i++)
                rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (lg - 1)); 
        }
        inline void dft(int *a, int sgn){
            for(int i = 0; i < len; i++)
                if(i < rev[i]) swap(a[i], a[rev[i]]);
            for(int k = 2; k <= len; k <<= 1){
                int w = Pow(G, (mod - 1) / k);
                if(sgn == -1) w = Pow(w, mod - 2);
                for(int i = 0; i < len; i += k){
                    int now = 1;
                    for(int j  = i; j < i + (k >> 1); j++){
                        int x = a[j], y = 1ll * a[j+(k>>1)] * now % mod;
                        a[j] = x + y >= mod ? x + y - mod : x + y;
                        a[j+(k>>1)] = x - y < 0 ? x - y + mod : x - y;
                        now = 1ll * now * w % mod;
                    }
                }
            }
            if(sgn == -1){
                int Inv = Pow(len, mod - 2);
                for(int i = 0; i < len; i++) a[i] = 1ll * a[i] * Inv % mod;
            }
        }
    }
    using poly::timesinit;
    using poly::Pow;
    using poly::dft;
    int main(){
        read(D), read(n), read(m);
        js[0] = 1, inv[0] = 1;
        for(int i = 1; i <= D; i++){
            js[i] = 1ll * js[i-1] * i  % mod; 
            inv[i] = Pow(js[i], mod - 2);
        }
        for(int i = 0; i <= D; i++){
            a[i] = 1ll * inv[i] * Pow((D - 2 * i + mod) % mod, n) % mod;
            if(i & 1) a[i] = mod - a[i];
            b[i] = inv[i];
        }
        timesinit(D + D + 1);
        dft(a, 1), dft(b, 1);
        for(int i = 0; i < poly::len; i++) 
            a[i] = 1ll * a[i] * b[i] % mod;
        dft(a, -1);
        for(int i = D + 1; i < poly::len; i++) a[i] = 0;
        for(int i = 0; i <= D; i++){
            a[i] = 1ll * a[i] * Pow(Pow(2, i), mod - 2) % mod;
            a[i] = 1ll * a[i] * js[D] % mod * inv[i] % mod * inv[D-i] % mod;
            a[i] = 1ll * a[i] * js[i] % mod;
            a[i] = 1ll * a[i] * js[i] % mod;
            if(i & 1) a[i] = (mod - a[i]) % mod;
        }
        reverse(a, a + D + 1);
        dft(a, 1);
        for(int i = 0; i < poly::len; i++) 
            a[i] = 1ll * a[i] * b[i] % mod;
        dft(a, -1);
        for(int i = 0; i <= min(n - 2 * m, D); i++){
            int x = 1ll * a[D-i] * inv[i] % mod;
            if(i & 1) x = (mod - x) % mod;
            ans = (ans + x) % mod;
        }
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    微信小程序反编译
    Mac 绑定Gitlab或者GitHub帐号,从新生成公钥
    Vue调试工具vue-devtools安装及使用
    NPM和Yarn添加淘宝镜像
    权限菜单设计
    Axure RP 7.0注册码
    Mac用户抓包软件Charles 4.0 破解 以及 抓取Https链接设置
    [转]c++导出函数dll供c#调用
    ef(EntityFramework)动态传递数据库连接字符串
    [转]sqlserver查询系统表统计表行数和占用空间
  • 原文地址:https://www.cnblogs.com/mangoyang/p/11200776.html
Copyright © 2020-2023  润新知