BZOJ3625: [Codeforces Round #250]小朋友和二叉树(OGF+牛顿迭代)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/79123706

传送门

题解:

看到这种二叉树的题第一反应就是类似卡特兰数的递推。或者另外一种直观的想法是看成一个点和两边的二叉树的拼接,注意这里不带标号。

那么很简单了,对于点和二叉树分别构造OGF:g(x),f(x),那么:

f=gf2+1

解二次方程:
f=21±1g2

舍去减的根,因为它在0处不收敛。
f=21+1g2

然后直接牛顿迭代即可,具体可以参考这里

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
inline int rd() {
    char ch=getchar(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
    return i*f;
}
inline void W(int x){
    static int buf[50];
    if(!x) {putchar('0'); return;}
    if(x<0) {putchar('-'); x=-x;}
    while(x) {buf[++buf[0]]=x%10; x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+'0');
}
const int N=1e5+50;
const int Mod=998244353;
const int G=3;
const int inv2=499122177;
inline int power(int a,int b) {
    int rs=1; 
    for(;b;b>>=1,a=(LL)a*a%Mod) if(b&1) rs=(LL)rs*a%Mod;
    return rs;
}
int n,m,k,bb[N*8],f[N*8],g[N*8],ig[N*8],tp[N*8],tp2[N*8],w[N*8],pos[N*8];
inline void dft(int *a) {
    for(int i=1;i<k;i++) pos[i]=(i&1) ?((pos[i>>1]>>1)^(k>>1)) :(pos[i>>1]>>1);
    for(int i=1;i<k;i++) if(pos[i]>i) swap(a[pos[i]],a[i]);
    for(int bl=1;bl<k;bl<<=1) {
        int tl=bl<<1,wn=power(G,(Mod-1)/tl); w[0]=1;
        for(int i=1;i<bl;i++) w[i]=(LL)w[i-1]*wn%Mod;
        for(int bg=0;bg<k;bg+=tl)
            for(int j=0;j<bl;j++) {
                int &t1=a[bg+j],&t2=a[bg+j+bl],t3=(LL)t2*w[j]%Mod;
                t2=(t1-t3<0?t1-t3+Mod:t1-t3);
                t1=(t1+t3>=Mod?t1+t3-Mod:t1+t3);
            }
    } 
}
inline void calc_inverse(int *a,int *b,int len) {
    if(len==1) {b[0]=power(a[0],Mod-2); return;}
    if(len!=1) calc_inverse(a,b,len>>1);
    k=len<<1;
    for(int i=0;i<len;i++) tp[i]=b[i];
    for(int i=(len>>1);i<len;i++) tp[i]=0;
    for(int i=0;i<len;i++) tp2[i]=a[i];
    for(int i=len;i<k;i++) tp[i]=(tp2[i]=0);
    dft(tp); dft(tp2);
    for(int i=0;i<k;i++) tp[i]=(2ll*tp[i]%Mod - (LL)tp2[i]*tp[i]%Mod*tp[i]%Mod +Mod)%Mod;
    dft(tp); reverse(tp+1,tp+k);
    const int inv=power(k,Mod-2);
    for(int i=0;i<len;i++) b[i]=(LL)tp[i]*inv%Mod;
    for(int i=len;i<k;i++) b[i]=0;
}
inline void calc_root(int *a,int *b,int len) {
    if(len==1) {b[0]=sqrt(a[0]); return;}
    if(len!=1) calc_root(a,b,len>>1);
    k=len<<1; 
    for(int i=0;i<len;i++) b[i]=b[i]*2%Mod;
    calc_inverse(b,ig,len);
    for(int i=0;i<len;i++) tp[i]=a[i];
    for(int i=0;i<len;i++) tp2[i]=ig[i];
    for(int i=len;i<k;i++) (tp[i]=(tp2[i]=0));
    dft(tp); dft(tp2); 
    for(int i=0;i<k;i++) tp[i]=(LL)tp[i]*tp2[i]%Mod;
    dft(tp); reverse(tp+1,tp+k);
    const int inv=power(k,Mod-2);
    for(int i=0;i<k;i++) tp[i]=(LL)tp[i]*inv%Mod;
    for(int i=0;i<len;i++) b[i]=(tp[i]+(LL)b[i]*inv2%Mod*inv2%Mod)%Mod;
    for(int i=len;i<k;i++) b[i]=0; 
}
int main() {
    n=rd(),m=rd(); bb[0]=1;
    for(int i=1;i<=n;i++) bb[rd()]=Mod-4;
    int len; for(len=1;len<=m;len<<=1);
    calc_root(bb,f,len); f[0]++;
    calc_inverse(f,g,len);
    for(int i=1;i<=m;i++) g[i]=g[i]*2%Mod;
    for(int i=1;i<=m;i++) W(g[i]),putchar('\n');
}
展开阅读全文

没有更多推荐了,返回首页