bzoj3625

Posted 123456

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n", a[i] * 2 % P);
    return 0;
}
View Code

 

以上是关于bzoj3625的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3625

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

BZOJ 3625 多项式求逆+多项式开根

bzoj 3625(CF 438E)The Child and Binary Tree——多项式开方

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

NTT+多项式求逆+多项式开方(BZOJ3625)