zoukankan      html  css  js  c++  java
  • bzoj3625

    fft

    分治虽然是万能的,但是太慢了

    分治是nlog^2n的,太慢了,于是我们用求逆和开根

    设f(x)表示答案为x的方案数

    c表示物品的生成函数

    那么f=f*f*c+1

    f*f表示左右儿子的方案数

    c表示根的方案数

    +1是空树,也就是+上t(x)=1这个生成函数

    然后求根公式得出f=2/(1+sqrt(1-4*g))

    为什么是+号呢?因为x=1时方案数=1,那么只能是+号

    然后就是多项式开根和求逆

    具体看picks博客

    然后是卡常

    所有数组开int

    fft蝴蝶操作一定要开int

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int P = 998244353;
    ll power(ll x, int t)
    {
        ll ret = 1;
        for(; t; t >>= 1, x = x * x % P) if(t & 1) ret = ret * x % P;
        return ret;
    }
    const int N = (1 << 18) + 2;
    int n, k, m;
    int rev[N];
    ll inv2;
    void ntt(int *a, int n, int k, int f)
    {
        for(int i = 0; i < n; ++i) if(i < rev[i]) swap(a[i], a[rev[i]]);
        for(int l = 2; l <= n; l <<= 1)
        {
            ll w = power(3, f == 1 ? (P - 1) / l : P - 1 - (P - 1) / l);
            int m = l >> 1;
            for(int i = 0; i < n; i += l) 
            {
                ll t = 1;
                for(int k = 0; k < m; ++k, t = t * w % P) 
                {
                    int x = a[i + k], y = t * a[i + k + m] % P;
                    a[i + k] = (x + y) % P;
                    a[i + m + k] = (x - y + P) % P;
                }
            }
        }
        if(f == -1)
        {
            ll inv = power(n, P - 2);
            for(int i = 0; i < n; ++i) a[i] = a[i] * inv % P;
        }
    }
    int a[N], b[N], tmp[N], B[N], c[N];
    void poly_inverse(int *a, int *b, int l)
    {
        if(l == 1) 
        {
            b[0] = power(a[0], P - 2);
            return;
        }
        poly_inverse(a, b, l >> 1);
        int n = 1, k = 0;
        while(n <= l) n <<= 1, ++k;
        for(int i = 0; i < n; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
        for(int i = 0; i < l; ++i) tmp[i] = a[i];
        for(int i = l; i < n; ++i) tmp[i] = 0;
        ntt(tmp, n, k, 1);
        ntt(b, n, k, 1);
        for(int i = 0; i < n; ++i) b[i] = (ll)b[i] * (2 - (ll)tmp[i] * b[i] % P + P) % P;
        ntt(b, n, k, -1);
        for(int i = l; i < n; ++i) b[i] = 0;
    }
    void poly_sqrt(int *a, int *b, int l)
    {
        if(l == 1) 
        {
            b[0] = 1;
            return;
        }
        int n = 1, k = 0;    
        while(n <= l) n <<= 1, ++k;
        poly_sqrt(a, b, l >> 1);
        for(int i = 0; i < n; ++i) B[i] = 0;
        poly_inverse(b, B, l);
        for(int i = 0; i < n; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
        for(int i = 0; i < l; ++i) tmp[i] = a[i];
        for(int i = l; i < n; ++i) tmp[i] = 0, B[i] = 0;
        ntt(B, n, k, 1);
        ntt(tmp, n, k, 1);
        ntt(b, n, k, 1);
        for(int i = 0; i < n; ++i) b[i] = (ll)inv2 * (b[i] + (ll)B[i] * tmp[i] % P) % P;
        ntt(b, n, k, -1);
        for(int i = l; i < n; ++i) b[i] = 0;
    }
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i) 
        {
            int x;
            scanf("%d", &x);
            c[x] -= 4;
        }
        inv2 = power(2, P - 2);
        int len = 1;
        while(len <= m) len <<= 1;
        ++c[0];
        for(int i = 1; i <= m; ++i) if(c[i] < 0) c[i] += P;
        poly_sqrt(c, b, len);
        ++b[0];
        b[0] %= P;
        poly_inverse(b, a, len);
        for(int i = 1; i <= m; ++i) printf("%d
    ", a[i] * 2 % P);
        return 0;
    }
    View Code
  • 相关阅读:
    【洛谷 2212】浇地Watering the Fields
    【洛谷 2504】聪明的猴子
    【洛谷 1991】无线通讯网
    【洛谷 3366】最小生成树_Prim
    Spark RDD中两种算子之一:常见Action算子小结
    Spark学习之路Spark之RDD
    Linux系统之pssh系列工具的使用
    MapReduce shuffle过程详解
    批量计算和流式计算
    关于IDEA破解后无法启动问题
  • 原文地址:https://www.cnblogs.com/19992147orz/p/8063827.html
Copyright © 2011-2022 走看看