• BZOJ 3625: [Codeforces Round #250]小朋友和二叉树


    3625: [Codeforces Round #250]小朋友和二叉树

    Time Limit: 40 Sec  Memory Limit: 256 MB
    Submit: 304  Solved: 130
    [Submit][Status][Discuss]

    Description

    我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树。
    考虑一个含有n个互异正整数的序列c[1],c[2],...,c[n]。如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{c[1],c[2],...,c[n]}中,我们的小朋友就会将其称作神犇的。并且他认为,一棵带点权的树的权值,是其所有顶点权值的总和。
    给出一个整数m,你能对于任意的s(1<=s<=m)计算出权值为s的神犇二叉树的个数吗?请参照样例以更好的理解什么样的两棵二叉树会被视为不同的。
    我们只需要知道答案关于998244353(7*17*2^23+1,一个质数)取模后的值。

    Input

    第一行有2个整数 n,m(1<=n<=10^5; 1<=m<=10^5)。
    第二行有n个用空格隔开的互异的整数 c[1],c[2],...,c[n](1<=c[i]<=10^5)。

    Output

    输出m行,每行有一个整数。第i行应当含有权值恰为i的神犇二叉树的总数。请输出答案关于998244353(=7*17*2^23+1,一个质数)取模后的结果。

    Sample Input

    样例一:
    2 3
    1 2
    样例二:
    3 10
    9 4 3
    样例三:
    5 10
    13 10 6 4 15

    Sample Output

    样例一:
    1
    3
    9
    样例二:
    0
    0
    1
    1
    0
    2
    4
    2
    6
    15
    样例三:
    0
    0
    0
    1
    0
    1
    0
    2
    0
    5

    HINT

    对于第一个样例,有9个权值恰好为3的神犇二叉树:

    Source

    [Submit][Status][Discuss]

    据说是道生成函数+多项式计算水题,所以机房里只有我这样的蒟蒻才不会做。

    设F(x)中的i次方项系数表示权值和为i的二叉树的个数。(这个就是最终答案函数)

    设C(x)中的i次方项系数表示权值i是否出现在可选集合内。(这其实就是C集合的bitset表示)

    然后得到$F=CF^2+1$,其中C为枚举根节点权值,两个F分别是左右子树,+1代表可能是一棵空树。

    化简得到$CF^2-F+1=0$,根据一元二次方程求根公式,这个多项式方程的根就是$frac{1pmsqrt{1-4C}}{2C}$。

    然后嘞,就支持一下多项式开方,多项式求逆好了,其中需要用到NTT和两个倍增算法,然而蒟蒻的我并不会,只好向Monster_Yi大佬和LincHpin大爷虚心请教。

      1 #include <cstdio>
      2 #include <cstring>
      3 
      4 template <class T>
      5 inline void read(T &x)
      6 {
      7     x = 0;
      8     char c = getchar();
      9     while (c < 48)c = getchar();
     10     while (c > 47)x = x*10 + c - 48, c = getchar();
     11 }
     12 
     13 template <class T>
     14 inline void swap(T &a, T &b)
     15 {
     16     T c;
     17     c = a;
     18     a = b;
     19     b = c;
     20 }
     21 
     22 const int P = 998244353;
     23 const int D = 499122177;
     24 const int N = 550000;
     25 
     26 inline int pow(int a, int b)
     27 {
     28     int r = 1;
     29     
     30     while (b)
     31     {
     32         if (b & 1)
     33             r = 1LL * r * a % P;
     34         
     35         b >>= 1, a = 1LL * a * a % P;
     36     }
     37     
     38     return r;
     39 }
     40 
     41 inline void ntt(int *a, int len, int type)
     42 {
     43     for (int i = 0, t = 0; i < len; ++i)
     44     {
     45         if (i > t)swap(a[i], a[t]);
     46         for (int j = (len >> 1); (t ^= j) < j; j >>= 1);
     47     }
     48     
     49     for (int h = 2; h <= len; h <<= 1)
     50     {
     51         int wn = pow(5, (P - 1) / h);
     52         
     53         for (int i = 0; i < len; i += h)
     54         {
     55             int wk = 1;
     56             
     57             for (int j = 0; j < (h >> 1); ++j, wk = 1LL * wk * wn % P)
     58             {
     59                 int t = 1LL * wk * a[i + j + (h >> 1)] % P;
     60                 
     61                 a[i + j + (h >> 1)] = (a[i + j] - t + P) % P;
     62                 a[i + j] = (a[i + j] + t) % P;
     63             }
     64         }
     65     }
     66     
     67     if (type == -1)
     68     {
     69         for (int i = 1; i < (len >> 1); ++i)
     70             swap(a[i], a[len - i]);
     71         
     72         int inv = pow(len, P - 2);
     73         
     74         for (int i = 0; i < len; ++i)
     75             a[i] = 1LL * a[i] * inv % P;
     76     }
     77 }
     78 
     79 void inv(int *a, int *b, int len)
     80 {
     81     if (len == 1)
     82         b[0] = pow(a[0], P - 2);
     83     else
     84     {
     85         static int t[N];
     86         
     87         inv(a, b, len >> 1);
     88         
     89         memcpy(t,         a, len * sizeof(int));
     90         memset(t + len,    0, len * sizeof(int));
     91         
     92         ntt(t, len << 1, 1);
     93         ntt(b, len << 1, 1);
     94         
     95         for (int i = 0; i < len << 1; ++i)
     96             b[i] = 1LL * b[i] * (2 - 1LL * t[i] * b[i] % P + P) % P;
     97     
     98         ntt(b, len << 1, -1);
     99         
    100         memset(b + len,    0, len * sizeof(int));
    101     }
    102 }
    103 
    104 void sqrt(int *a, int *b, int len)
    105 {
    106     if (len == 1)
    107         b[0] = 1;
    108     else
    109     {
    110         static int c[N], d[N];
    111         
    112         sqrt(a, b, len >> 1);
    113         
    114         memset(d,        0, len * sizeof(int));
    115         memset(d + len, 0, len * sizeof(int));
    116         
    117         inv(b, d, len);
    118         
    119         memcpy(c,         a, len * sizeof(int));
    120         memset(c + len, 0, len * sizeof(int));
    121         
    122         ntt(c, len << 1, 1);
    123         ntt(b, len << 1, 1);
    124         ntt(d, len << 1, 1);
    125         
    126         for (int i = 0; i < len << 1; ++i)
    127             b[i] = (1LL * c[i] * d[i] % P + b[i]) % P * D % P;
    128             
    129         ntt(b, len << 1, -1);
    130         
    131         memset(b + len, 0, len * sizeof(int));
    132     }
    133 }
    134 
    135 int n, m, len;
    136 
    137 int a[N], b[N];
    138 
    139 signed main(void)
    140 {
    141     read(n);
    142     read(m);
    143 
    144     a[0] = 1;
    145 
    146     for (len = 1; len <= m; len <<= 1);
    147     
    148     for (int i = 1, x; i <= n; ++i)
    149         if (read(x), x <= m)a[x] = P - 4;
    150     
    151     sqrt(a, b, len);
    152     
    153     memcpy(a, b, len * sizeof(int)), ++a[0];
    154     memset(b, 0, len * sizeof(int)), inv(a, b, len);
    155     memcpy(a, b, len * sizeof(int));
    156     
    157     for (int i = 1; i <= m; ++i)
    158         printf("%d
    ", (a[i] << 1) % P);
    159 }

    @Author: YouSiki

  • 相关阅读:
    PS教程1000例
    [LeetCode] Ransom Note 赎金条
    Android LinkedList和ArrayList的区别
    Android 一种非常好用的Android屏幕适配
    Android MVC模式和MVP模式的区别
    Android 性能优化的方面方面都在这儿
    Android 高级面试题及答案
    Android的事件分发(dispatchTouchEvent),拦截(onInterceptTouchEvent)与处理(onTouchEvent)
    android studio 3.0 以上 查看sharedpreference
    Android adb命令查看sharedpreferences
  • 原文地址:https://www.cnblogs.com/yousiki/p/6426256.html
Copyright © 2020-2023  润新知