1. 程式人生 > >BZOJ3625: [Codeforces Round #250]小朋友和二叉樹(OGF+牛頓迭代)

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

傳送門

題解:

看到這種二叉樹的題第一反應就是類似卡特蘭數的遞推。或者另外一種直觀的想法是看成一個點和兩邊的二叉樹的拼接,注意這裡不帶標號。

那麼很簡單了,對於點和二叉樹分別構造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'); }