• CF 438E The Child and Binary Tree


    BZOJ 3625

    吐槽

    BZOJ上至今没有卡过去,太慢了卡得我不敢交了……

    一件很奇怪的事情就是不管是本地还是自己上传数据到OJ测试都远远没有到达时限。

    本题做法

    设$f_i$表示权值为$i$的二叉树的个数,因为一棵二叉树可以通过左右儿子构建起来转移,我们可以得到转移:

    $$f_w = sum_{x, y, w - (x + y) in c} f_x * f_y$$

    注意到左右子树可以为空,所以$f_0 = 1$。

    很容易发现这是一个卷积的形式,我们尝试把它写得好看一点。

    先把物品写成生成函数的形式,记

    $$G(x) = sum_{i = 0}^{m}[i in c]x^i$$

    题目保证了$G(0) = 0$。

    再用$F(x)$表示权值为$x$的二叉树的个数,有

    $$F(n) = sum_{i = 1}^{n}G(i)sum_{j = 1}^{n - i}F(j)F(n - i - j)$$

    $$F(n) = (G * F ^ 2)(n)$$

    发现多项式$F$除了第$0$项每一项都可以由上面这个式子得到,而$F(0) = 1$。

    得到

    $$F = G * F ^ 2 + 1$$

    解一元二次方程,

    $$F = frac{2}{1 pm sqrt{1 - 4G}}$$

    考虑到$G(0) = 0$,$F(0) = 1$,所以取加号。

    剩下就是怎么开根的问题。

    多项式开根

    假设已经求出了$F_0(x)$使$G(F_0(x)) equiv 0 (mod x^{left lceil frac{n}{2} ight ceil})$成立,要求$F(x)$使$G(F(x)) equiv 0 (mod x^n)$成立。

    在多项式$exp$那里已经提过了这里$G(F(x)) = F(x)^2 - A(x)$。

    牛顿迭代的式子拿出来,

    $$F(x) equiv F_0(x) - frac{G(F_0(x))}{G'(F_0(x))}( mod x^n)$$

    $$G'(F(x)) = 2F(x)$$

    代进去

    $$F(x) equiv frac{F_0(x)^2 + A(x)}{2F_0(x)}(mod x^n)$$

    可以递归计算了。

    $$T(n) = T(frac{n}{2}) + O(nlogn)$$

    时间复杂度还是$O(nlogn)$,常数极大就是了。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N = 1 << 18;
    
    int n, m, a[N];
    ll f[N], g[N];
    
    namespace Poly {
        const int L = 1 << 18;
        const ll P = 998244353LL;
    
        int lim, pos[L];
        ll f[L], g[L], h[L], tmp[L];
        
        inline ll fpow(ll x, ll y) {
            ll res = 1;
            for (x %= P; y > 0; y >>= 1) {
                if (y & 1) res = res * x % P;
                x = x * x % P;
            }
            return res;
        }
        
        const ll inv2 = fpow(2, P - 2);
        
        inline void prework(int len) {
            int l = 0;
            for (lim = 1; lim < len; lim <<= 1, ++l);
            for (int i = 0; i < lim; i++)
                pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
        }
        
        inline void ntt(ll *c, int opt) {
            for (int i = 0; i < lim; i++)
                if (i < pos[i]) swap(c[i], c[pos[i]]);
            for (int i = 1; i < lim; i <<= 1) {
                ll wn = fpow(3, (P - 1) / (i << 1));
                if (opt == -1) wn = fpow(wn, P - 2);
                for (int len = i << 1, j = 0; j < lim; j += len) {
                    ll w = 1;
                    for (int k = 0; k < i; k++, w = w * wn % P) {
                        ll x = c[j + k], y = w * c[j + k + i] % P;
                        c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
                    }
                }
            }
            
            if (opt == -1) {
                ll inv = fpow(lim, P - 2);
                for (int i = 0; i < lim; i++) c[i] = c[i] * inv % P;
            }
        }
        
        void inv(ll *a, ll *b, int len) {
            if (len == 1) {
                b[0] = fpow(a[0], P - 2);
                return;
            }
            
            inv(a, b, (len + 1) >> 1);
            prework(len << 1);
            for (int i = 0; i < lim; i++) f[i] = g[i] = 0;
            for (int i = 0; i < len; i++) f[i] = a[i], g[i] = b[i];
            ntt(f, 1), ntt(g, 1);
            for (int i = 0; i < lim; i++)
                g[i] = g[i] * (2LL - g[i] * f[i] % P + P) % P;
            ntt(g, -1);
            
            for (int i = 0; i < len; i++) b[i] = g[i];
        }
        
        inline void direv(ll *c, int len) {
            for (int i = 0; i < len - 1; i++) c[i] = c[i + 1] * (i + 1) % P;
            c[len - 1] = 0;
        }
        
        inline void integ(ll *c, int len) {
            for (int i = len - 1; i > 0; i--) c[i] = c[i - 1] * fpow(i, P - 2) % P;
            c[0] = 0;
        }
        
        inline void ln(ll *a, ll *b, int len) {
            for (int i = 0; i < len; i++) h[i] = 0;
            inv(a, h, len);
                    
            for (int i = 0; i < len; i++) b[i] = a[i];
            direv(b, len);    
    
            prework(len << 1);
            ntt(h, 1), ntt(b, 1);
            for (int i = 0; i < lim; i++) b[i] = b[i] * h[i] % P;
            ntt(b, -1);
            
            integ(b, len);
        }
        
        ll F[L], G[L], H[L];
        void exp(ll *a, ll *b, int len) {
            if (len == 1) {
                b[0] = 1;
                return;
            }
            exp(a, b, (len + 1) >> 1);
            
            ln(b, F, len);
            F[0] = (a[0] % P + 1 - F[0] + P) % P;
            for (int i = 1; i < len; i++) F[i] = (a[i] - F[i] + P) % P;
            
            prework(len << 1);
            for (int i = len; i < lim; i++) F[i] = 0;
            for (int i = 0; i < lim; i++) G[i] = 0;
            for (int i = 0; i < len; i++) G[i] = b[i];
            ntt(F, 1), ntt(G, 1);
            for (int i = 0; i < lim; i++) F[i] = F[i] * G[i] % P;
            ntt(F, -1);
            
            for (int i = 0; i < len; i++) b[i] = F[i];
        }
        
        void sqr(ll *a, ll *b, int len) {
            if (len == 1) {
                b[0] = a[0];
                return;
            }
            
            sqr(a, b, (len + 1) >> 1);
            
            for (int i = 0; i < len; i++) H[i] = 0;
            inv(b, H, len);
            
            prework(len << 1);
            for (int i = 0; i < lim; i++) F[i] = G[i] = 0;
            for (int i = 0; i < len; i++) F[i] = a[i], G[i] = b[i];
            ntt(F, 1), ntt(G, 1), ntt(H, 1);
            for (int i = 0; i < lim; i++) 
                F[i] = (G[i] * G[i] % P + F[i] + P) % P * inv2 % P * H[i] % P;
            ntt(F, -1);
            
            for (int i = 0; i < len; i++) b[i] = F[i];
        }
        
    };
    
    using Poly :: fpow;
    using Poly :: P;
    
    /*  template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for (; ch > '9'|| ch < '0'; ch = getchar())
            if (ch == '-') op = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }    */
    
    namespace Fread {
        const int L = 1 << 15;
        
        char buffer[L], *S, *T;
        
        inline char Getchar() {
            if(S == T) {
                T = (S = buffer) + fread(buffer, 1, L, stdin);
                if(S == T) return EOF;
            }
            return *S++;
        }
        
        template <class T> 
        inline void read(T &X) {
            char ch; T op = 1;
            for(ch = Getchar(); ch > '9' || ch < '0'; ch = Getchar())
                if(ch == '-') op = -1;
            for(X = 0; ch >= '0' && ch <= '9'; ch = Getchar()) 
                X = (X << 1) + (X << 3) + ch - '0'; 
            X *= op;
        }
        
    } using namespace Fread;   
    
    namespace Fwrite {
        const int L = 2e6 + 5;
    
        int bufp = 0;
        char buf[L]; 
          
        template <typename T>
        inline void write(T x) {
            if(!x) buf[++bufp] = '0';
            
            if(x < 0) {
                buf[++bufp] = '-';
                x = -x;
            }
            int st[15], tp = 0;
            for(; x; x /= 10) st[++tp] = x % 10;
            for(; tp; tp--) buf[++bufp] = (st[tp] + '0');
            buf[++bufp] = '
    ';
        }   
        
    
    } using namespace Fwrite;
    
    template <typename T>
    inline void inc(T &x, T y) {
        x += y;
        if (x >= P) x -= P;
    }
    
    template <typename T>
    inline void sub(T &x, T y) {
        x -= y;
        if (x < 0) x += P;
    }
    
    int main() {
    /*    #ifndef ONLINE_JUDGE
            freopen("Sample.txt", "r", stdin);
        #endif    */
        
    //    freopen("3625.in", "r", stdin);
    //    freopen("3625.out", "w", stdout);
        
        read(n), read(m);
        for (int x, i = 1; i <= n; i++) {
            read(x);
            if (x <= m) g[x] = 1;
        }
        
    /*    for (int i = 0; i <= m; i++)
            printf("%lld%c", g[i], " 
    "[i == m]);   */
        
        g[0] = 1;
        for (int i = 1; i <= m; i++) g[i] = (P - 4LL * g[i] % P) % P;
        Poly :: sqr(g, f, m + 1);
        
    /*    for (int i = 0; i <= m; i++)
            printf("%lld%c", g[i], " 
    "[i == m]);   
        
        for (int i = 0; i <= m; i++)
            printf("%lld%c", f[i], " 
    "[i == m]);   */
    
        inc(f[0], 1LL);
        for (int i = 0; i <= m; i++) g[i] = 0;
        Poly :: inv(f, g, m + 1);
        
    /*    for (int i = 0; i <= m; i++)
            printf("%lld%c", f[i], " 
    "[i == m]);   */
    
        
        for (int i = 1; i <= m; i++) {
    //        write(g[i] * 2LL % P);
    //        printf("
    ");
            printf("%lld
    ", (g[i] + g[i]) % P);
        }
        
    //    fwrite(buf + 1, 1, bufp, stdout);    
        return 0;
    }
    View Code
  • 相关阅读:
    SpringBoot HATEOAS用法简介
    犀函
    dubbo 相关面试题 有用(转)
    想使用消息队列,先考虑下这些问题!
    appium在Mac上环境搭建
    3. SOFAJRaft源码分析— 是如何进行选举的?
    Redis相关知识
    替代微信ipad协议(转)
    c#面试题(1)(转)
    例题6-5 Boxes in a line uVa12657
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10280368.html
Copyright © 2020-2023  润新知