質問への良いモデル
カウントラベルの数はとても正当な木になってきました。
法的規制:
1.符号ルートサブツリーはより大きい
2.息子がすべての葉である場合、Bの数があります
3.息子ではなく、葉がある場合は、Aの数があります
そして、DPを考えます
直接列挙ルート息子の場合
CDQパーティションNTTは非常に嫌です
だけでなく、彼自身のロールがある、またはお互いをロール
いくつかの簡素化と翻訳した後、それはフォームのCDQパーティションNTTに変換することができます。
どのようにどのように良いことができません。
とにかく、私は最終的にプッシュ式は次のような特徴を(公式には書いていない)があります。
便宜上、インペリアルG [0]、F [0]、G [1]、fは[1]が0であります
Fの場合は、その後、パン、右の瞬間、固定された、とは、テンプレートのタイトルのCDQパーティションです
両者はないG用、場合仕切り部LのCDQない0 Fに[L、中間]として、[QL、QR]としてG、およびG [L、中間]として、[QR、QL]としてFすべての上
これは実際に休止G [N] = G [0] * F [N]であるが、G [0] = 0、ように制御していません
コード:
const int N=240000+5; int jie[N],inv[N]; int f[N],g[N]; int n,sa,sb; int ta[N],b[N],a[N]; void divi(int l,int r,int ql,int qr){ // cout<<" divi "<<l<<" "<<r<<" ql "<<ql<<" qr "<<qr<<endl; if(l==0&&r==1){ f[0]=f[1]=g[0]=g[1]=0; return; } if(l==r){ f[l]=ad(mul(f[l],jie[l-1]),b[l-1]); g[l]=ad(f[l],mul(g[l],jie[l-1])); f[l]=mul(f[l],inv[l-1]); g[l]=mul(g[l],inv[l]); return; } int mid=(l+r)>>1; int qmd=(ql+qr)>>1; divi(l,mid,ql,qmd); Poly A,G; A.resize(qr-ql+1); G.resize(mid-l+1); for(reg i=ql;i<=qr;++i){ A[i-ql]=a[i]; } for(reg i=l;i<=mid;++i){ G[i-l]=g[i]; } A*=G; for(reg i=mid+1;i<=r;++i){ f[i]=ad(f[i],A[i-l]); } if(l==0){ Poly F;G.clear(); F.resize(mid-l+1); G.resize(mid-l+1); for(reg i=l;i<=mid;++i){ F[i-l]=f[i]; G[i-l]=g[i]; } F=F*G; for(reg i=mid+1;i<=r;++i){ g[i]=ad(g[i],F[i]); } }else{ Poly F;G.clear(); F.resize(qr-ql+1); G.resize(mid-l+1); for(reg i=l;i<=mid;++i){ G[i-l]=g[i]; } for(reg i=ql;i<=qr;++i){ F[i-ql]=f[i]; } F=F*G; for(reg i=mid+1;i<=r;++i){ g[i]=ad(g[i],F[i-l]); } F.clear();G.clear(); F.resize(mid-l+1); G.resize(qr-ql+1); for(reg i=ql;i<=qr;++i){ G[i-ql]=g[i]; } for(reg i=l;i<=mid;++i){ F[i-l]=f[i]; } F=F*G; for(reg i=mid+1;i<=r;++i){ g[i]=ad(g[i],F[i-l]); } } divi(mid+1,r,ql,qmd); } int main(){ rd(n);rd(sa);rd(sb);int x; for(reg i=1;i<=sa;++i){rd(x);ta[x]=1;} for(reg i=1;i<=sb;++i){rd(x);b[x]=1;} if(n==1){ puts("1");return 0; } int m; for(m=1;m<=n;m<<=1); jie[0]=1; for(reg i=1;i<=m;++i) jie[i]=mul(jie[i-1],i); inv[m]=qm(jie[m],mod-2); for(reg i=m-1;i>=0;--i) inv[i]=mul(inv[i+1],i+1); for(reg i=1;i<=m;++i){ a[i]=mul(ta[i-1],inv[i-1]); } a[0]=0; divi(0,m-1,0,m-1); ll ans=f[n]; ans=mul(ans,jie[n-1]); ot(ans); return 0; }
树形结构很巧妙啊
f,g互相卷的分治NTT第一次写,还是举一个0,1,2,3,4,5,6,7的例子最好理解了!