• 【CTS 2019】珍珠


    Problem

    Description

    (n) 个在范围 ([1,D]) 内的整数均匀随机变量。

    求至少能选出 (m) 个瓶子,使得存在一种方案,选择一些变量,并把选出来的每一个变量放到一个瓶子中,满足每个瓶子都恰好装两个值相同的变量的概率。

    请输出概率乘上 (D^n) 后对 (998244353) 取模的值。取模部分说明可参考 。

    Range

    (0le mle 10^9,1le nle 10^9,1le Dle 10^5)

    Algorithm

    (FFT) ,生成函数

    Mentality

    对于 (2m>n)(n-2m ge D) 的情况先特判掉。

    不难发现,设 (a_i) 为颜色 (i) 出现的次数,我们要求的就是能满足 (sum a_i mod 2 le n - 2m) 的方案数。

    (f_i) 为恰好有 (i) 种颜色出现次数为奇数的方案数,则有:

    [ans = sum_{i=0}^{n-2m} f_i ]

    写出 (f_i) 的表达式之后不太好求,我们需要令限制更少一点。

    考虑钦定 (i) 个颜色的出现次数为奇数,设 (h_i) 为,对于钦定的某 (i) 种颜色,使得出现次数为奇数,且其他颜色出现次数随意的方案数。

    (g_i = binom{D}{i} h_i) ,也就是对于每种不同的钦定方案,我们将其求和。

    那么根据定义,必然有等式:

    [g_i=sum binom{j}{i} f_j ]

    因为每个 (f_j) 都会被 (g_i) 中的 ( binom{j}{i}) 种钦定方案算到。

    利用指数形生成函数 (sum c^nfrac{x^i}{i!} = e^{cx}) 可得:

    [h_i = n![x^n](frac{e^x-e^{-x}}{2})^i(e^x)^{D-i}\ =frac{n!}{2^i}[x^n]sum_{j=0}^i binom{i}{j} e^{jx}(-e^{-x})^{i-j}e^{D-i}\ =frac{n!}{2^i}sum_{j=0}^i binom{i}{j} (-1)^{i-j}[x^n]e^{D+2j-2i}\ =frac{n!}{2^i}sum_{j=0}^i binom{i}{i-j} (-1)^{j}[x^n]e^{D-2j}\ ]

    随后因为 ([x^n]e^{cx}=frac{c^n}{n!}) ,直接代入得:

    [h_i =frac{n!}{2^i}sum_{j=0}^i binom{i}{i-j} (-1)^{j}frac{(D-2j)^n}{n!}\ =frac{i!}{2^i}sum_{j=0}^i frac{1}{(i-j)!}frac{(-1)^j(D-2j)^n}{j!} ]

    这样就可以卷积了。

    然后根据定义式直接算出 ({g_i})

    根据二项式反演可得:

    [f_i=sum_{j=i}^{D} (-1)^{j-i} binom{j}{i} g_j\ = sum_{j=0}^{D - i} (-1)^{j} binom{j + i}{i} g_{j + i}\ = frac{1}{i!}sum_{j=0}^{D - i} frac{(-1)^{j}}{j!} (j+i)!g_{j + i}\ ]

    (p_{D-j-i}=g_{j+i}(j+i)!),则有:

    [f_i= frac{1}{i!}sum_{j=0}^{D - i} frac{(-1)^{j}}{j!} p_{D-j-i}\ ]

    这样就可以卷积了。

    Code

    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define LL long long
    #define go(G, x, i, v) 
      for (int i = G.hd[x], v = G.to[i]; i; v = G.to[i = G.nx[i]])
    #define inline __inline__ __attribute__((always_inline))
    inline LL read() {
      LL x = 0, w = 1;
      char ch = getchar();
      while (!isdigit(ch)) {
        if (ch == '-') w = -1;
        ch = getchar();
      }
      while (isdigit(ch)) {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
      }
      return x * w;
    }
    
    const int Max_n = 8e5 + 5, mod = 998244353;
    
    int D, n, m;
    int fac[Max_n], ifac[Max_n];
    int f[Max_n], g[Max_n], G[Max_n];
    
    int ksm(int a, int b = mod - 2) {
      int res = 1;
      for (; b; b >>= 1, a = (LL)a * a % mod)
        if (b & 1) res = (LL)res * a % mod;
      return res;
    }
    
    namespace Poly {
    int len, bit, rev[Max_n];
    void init(int n) {
      len = 1 << (bit = log2(n) + 1);
      for (int i = 0; i < len; i++)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
    }
    void dft(int *f, bool t) {
      for (int i = 0; i < len; i++)
        if (rev[i] > i) swap(f[i], f[rev[i]]);
      for (int l = 1; l < len; l <<= 1) {
        int Wn = ksm(3, (mod - 1) / (l << 1));
        if (t) Wn = ksm(Wn);
        for (int i = 0; i < len; i += l << 1) {
          int Wnk = 1;
          for (int j = i; j < i + l; j++, Wnk = (LL)Wnk * Wn % mod) {
            int x = f[j], y = (LL)f[j + l] * Wnk % mod;
            f[j] = (x + y) % mod, f[j + l] = (x - y + mod) % mod;
          }
        }
      }
      if (t)
        for (int i = 0, Inv = ksm(len); i < len; i++) f[i] = (LL)f[i] * Inv % mod;
    }
    void Mul(int *f, int *g, int N) {
      init(N);
      dft(f, 0), dft(g, 0);
      for (int i = 0; i < len; i++) f[i] = (LL)f[i] * g[i] % mod;
      dft(f, 1), dft(g, 1);
    }
    }  // namespace Poly
    using namespace Poly;
    
    namespace Input {
    void main() { D = read(), n = read(), m = read(); }
    }  // namespace Input
    
    namespace Init {
    void main() {
      fac[0] = 1;
      for (int i = 1; i <= D; i++) fac[i] = (LL)fac[i - 1] * i % mod;
      ifac[D] = ksm(fac[D]);
      for (int i = D; i; i--) ifac[i - 1] = (LL)ifac[i] * i % mod;
    }
    }  // namespace Init
    
    namespace Solve {
    int C(int n, int m) {
      if (n < m || m < 0) return 0;
      return (LL)fac[n] * ifac[m] % mod * ifac[n - m] % mod;
    }
    void main() {
      if (2 * m > n) {
        puts("0");
        return;
      }
      if (D <= n - 2 * m) {
        printf("%d
    ", ksm(D, n));
        return;
      }
      for (int i = 0, t = 1; i <= D; i++, t *= -1) {
        G[i] = ifac[i];
        g[i] =
            (LL)(t + mod) * ksm((D - 2 * i + mod) % mod, n) % mod * ifac[i] % mod;
      }
      Mul(G, g, D + 1 << 1);
      for (int i = 0; i <= D; i++) G[i] = (LL)ksm(ksm(2, i)) * G[i] % mod * fac[i] % mod * C(D, i) % mod;
      for (int i = 0, t = 1; i <= D; i++, t *= -1) {
        g[i] = (LL)G[D - i] * fac[D - i] % mod;
        f[i] = (LL)(t + mod) * ifac[i] % mod;
      }
      Mul(f, g, D + 1 << 1);
      int ans = 0;
      for (int i = 0; i <= n - 2 * m; i++)
        (ans += (LL)f[D - i] * ifac[i] % mod) %= mod;
      cout << ans << endl;
    }
    }  // namespace Solve
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("3120.in", "r", stdin);
      freopen("3120.out", "w", stdout);
    #endif
      Input::main();
      Init::main();
      Solve::main();
    }
    
  • 相关阅读:
    H5图片裁剪升级版(手机版)
    仿IOS 开关按钮
    JS 数字转换为大写金额
    Unity UGUI——遮罩效果(Mask)
    AdTime:多屏时代下传统媒体的鼓起
    C语言中随机数相关问题
    在vc中使用xtremetoolkit界面库-----安装及环境配置
    初识HTML 5:关于它的三个三
    移动中间件产品的解决方式
    Android ListView 常见问题与使用总结
  • 原文地址:https://www.cnblogs.com/luoshuitianyi/p/12852875.html
Copyright © 2020-2023  润新知