• Codeforces 438E The Child and Binary Tree


    题目传送门

      传送点I

      传送点II

      传送点III

    题目大意

      每个点的权值$cin {c_{1}, c_{2}, cdots, c_{n}}$,问对于每个$1leqslant sleqslant m$有多少种不同的这样的有根二叉树满足所有点的点权和等于$s$。

      先考虑一下怎么用dp来做。

      设$f_{n}$表示点权和为$n$的满足条件的二叉树的个数,那么有:

    $f_{n} = sum_{c in C}sum_{i = 0}^{n - c}f_{i}f_{n - c - i}$

      初值满足$f_{0} = 1$。

      注意到右边的式子有点像卷积,考虑$f_{n}$的普通生成函数$F(x) = sum_{n = 0}f_{n}x^{n}$。

      将$F(x)$平方就能得到$fotimes f$的生成函数。我们用它替换右半边,得到了:

    $F(x) = sum_{c in C}x^{c}F^2(x) + 1$

      设某个常数$A = sum_{c in C}x^{c}$,则有$Acdot F^2(x) - F(x) + 1$。

      解得$F_{1}(x) = frac{1 + sqrt{1 - 4A}}{2A}, F_{2}(x) = frac{1 - sqrt{1 - 4A}}{2A} = frac{1 - (1 - 4A)}{2Asqrt{1 + 4A}} = frac{2}{sqrt{1 + 4A}}$。

      我们考虑$F_{1}(x)$的分母的常数项,它是2,分子的常数项为0,然后求逆的时候就会出事情。

      但是$F_{2}(x)$可以通过恒等变换使得分母的常数项为非0。

      然后做一次多项式开根,一次多项式求逆就做完了。

    Code

      1 /**
      2  * Codeforces
      3  * Problem#438E
      4  * Accepted
      5  * Time: 1091ms
      6  * Memory: 5100k
      7  */
      8 #include <bits/stdc++.h>
      9 using namespace std;
     10 typedef bool boolean;
     11 
     12 const int N = 262144;
     13 const int bzmax = 20;
     14 const int M = 998244353;
     15 const int g = 3;
     16 const int inv2 = (M + 1) >> 1;
     17 
     18 int qpow(int a, int p) {
     19     if (p < 0)
     20         p += M - 1;
     21     int rt = 1, pa = a;
     22     for ( ; p; p >>= 1, pa = pa * 1ll * pa % M)
     23         if (p & 1)
     24             rt = rt * 1ll * pa % M;
     25     return rt;
     26 }
     27 
     28 int add(int a, int b) {
     29     return ((a += b) >= M) ? (a - M) : (a);
     30 }
     31 
     32 int sub(int a, int b) {
     33     return ((a -= b) < 0) ? (a + M) : (a);
     34 }
     35 
     36 class NTT {
     37     public:
     38         int gn[bzmax], _gn[bzmax];
     39         
     40         NTT() {
     41             for (int i = 0, L = 2; i < bzmax; i++, L <<= 1) {
     42                 gn[i] = qpow(g, (M - 1) / L);
     43                 _gn[i] = qpow(g, -(M - 1) / L);
     44             }
     45         }
     46 
     47         void operator () (int* f, int len, int sgn) {
     48             for (int i = 1, j = len >> 1, k; i < len - 1; i++, j += k) {
     49                 if (i < j)
     50                     swap(f[i], f[j]);
     51                 for (k = len >> 1; j >= k; j -= k, k >>= 1);
     52             }
     53 
     54             for (int b = 2, t = 0; b <= len; b <<= 1, t++) {
     55                 int wn = ((sgn > 0) ? (gn[t]) : (_gn[t])), w = 1, hb = b >> 1;
     56                 for (int i = 0; i < len; i += b, w = 1)
     57                     for (int j = i; j < i + hb; j++, w = w * 1ll * wn % M) {
     58                         int a = f[j], b = f[j + hb] * 1ll * w % M;
     59                         f[j] = add(a, b);
     60                         f[j + hb] = sub(a, b);
     61                     }
     62             }
     63 
     64             if (sgn < 0) {
     65                 int invlen = qpow(len, -1);
     66                 for (int i = 0; i < len; i++)
     67                     f[i] = f[i] * 1ll * invlen % M;
     68             }
     69         }
     70 
     71         int correctLen(int n) {
     72             int m = 1;
     73             while (m < n)    m <<= 1;
     74             return m;
     75         }
     76 }NTT;
     77 
     78 template<typename T>
     79 void pcopy(T* ns, T* ne, const T* os) {
     80     for ( ; ns != ne; *ns = *os, ns++, os++);
     81 }
     82 
     83 template<typename T>
     84 void pfill(T* ps, T* pt, T val) {
     85     for ( ; ps != pt; *ps = val, ps++);
     86 }
     87 
     88 void debug(const int* f, int n) {
     89     for (int i = 0; i < n; i++)
     90         cerr << f[i] << " ";
     91     cerr << endl;
     92 }
     93 
     94 void pol_inverse(int *f, int *g, int n) {
     95     static int h[N];
     96     if (n == 1)
     97         g[0] = qpow(f[0], -1);
     98     else {
     99         pol_inverse(f, g, (n + 1) >> 1);
    100 
    101         int t = NTT.correctLen(n << 1 | 1);
    102         pcopy(h, h + n, f);
    103         pfill(h + n, h + t, 0);
    104         NTT(h, t, 1);
    105         NTT(g, t, 1);
    106         for (int i = 0; i < t; i++)
    107             g[i] = g[i] * 1ll * sub(2, g[i] * 1ll * h[i] % M) % M;
    108         NTT(g, t, -1);
    109         pfill(g + n, g + t, 0);
    110     }
    111 }
    112 
    113 void pol_sqrt(int *f, int *g, int n) {
    114     static int C[N], D[N];
    115     if (n == 1)
    116         g[0] = 1;
    117     else {
    118         pol_sqrt(f, g, (n + 1) >> 1);
    119         
    120         int t = NTT.correctLen(n << 1);
    121         pcopy(C, C + n, f);
    122         pfill(C + n, C + t, 0);
    123         pfill(D, D + t, 0);
    124         pol_inverse(g, D, n);
    125         NTT(C, t, 1);
    126         NTT(D, t, 1);
    127         NTT(g, t, 1);
    128         for (int i = 0; i < t; i++)
    129             g[i] = add(C[i] * 1ll * D[i] % M, g[i]) * 1ll * inv2 % M;
    130         NTT(g, t, -1);
    131         pfill(g + n, g + t, 0);
    132     }
    133 }
    134 
    135 int n, m;
    136 int C[N], qC[N];
    137 
    138 inline void init() {
    139     scanf("%d%d", &n, &m);
    140     for (int i = 1, x; i <= n; i++) {
    141         scanf("%d", &x);
    142         if (x <= m)
    143             C[x] = -4;
    144     }
    145 }
    146 
    147 inline void solve() {
    148     C[0]++, m++;
    149     pol_sqrt(C, qC, m);
    150     qC[0]++;
    151     pfill(C, C + m, 0);
    152     pol_inverse(qC, C, m);
    153     for (int i = 1; i < m; i++)
    154         printf("%d
    ", add(C[i], C[i]));
    155 }
    156 
    157 int main() {
    158     init();
    159     solve();
    160     return 0;
    161 }
  • 相关阅读:
    python学习笔记
    【JavaScript】如何判断一个对象是未定义的?(已解决)
    【Eclipse】一个简单的 RCP 应用 —— 显示Eclipse 的启动时间。
    Win7 系统如何关闭休眠功能?(已解决)
    【Eclipse】Ubuntu 下菜单栏失效了,怎么办?(已解决)
    【Ubuntu】更新系统时出现Hash校验和不符的错误(已解决)
    【wget】一条命令轻松备份博客(包括图片)
    【Eclipse】启动时报错:No Java virtual machine (已解决)
    git 命令自动补全
    快马和慢马
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9727428.html
Copyright © 2020-2023  润新知