# loj6402 校门外的树(dp，多项式求逆)

https://loj.ac/problem/6402

(把这些点分成$p[x]<p[j]$，$p[x]>p[j]>p[i]$两种情况讨论就可以了)

$f(n)=n!-\sum\limits_{i=1}^{n-1} i! f(n-i)$

$dp(n)=\sum\limits_{i=0}^{n} (n-i) f(n-i) dp(i)$

$dp(n)=\sum\limits_{i=0}^{n} h(n-i) dp(i)$

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const ll mod=998244353,B=3;
const int maxn=1e7+7;
ll n,g[maxn],h[maxn],ginv[maxn],hinv[maxn],X[maxn];

aa=0;char cc=getchar();T ff=1;
while((cc!='-')&&(cc<'0'||cc>'9')) cc=getchar();
if(cc=='-') ff=-1,cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
aa*=ff;
}

ll qp(ll x,ll k) {
ll rs=1;
while(k) {
if(k&1) rs=rs*x%mod;
k>>=1; x=x*x%mod;
}
return rs;
}

ll finv(ll x) {return qp(x,mod-2);}

ll qp1(ll x,ll k) {
if(k<0) return qp(finv(x),-k);
return qp(x,k);
}

for(int i=1,j=len>>1,k;i<len-1;++i) {
if(i<j) swap(F[i],F[j]);
k=len>>1;
while(j>=k) {j-=k;k>>=1;}
if(j<k) j+=k;
}
}

void FFT(ll F[],ll len,ll on) {
for(int h=2;h<=len;h<<=1) {
ll wn=qp1(B,(mod-1)*on/h);
for(int j=0;j<len;j+=h) {
ll w=1;
for(int i=j;i<j+h/2;++i) {
ll u=F[i],v=w*F[i+h/2]%mod;
F[i]=(u+v)%mod;
F[i+h/2]=(u-v+mod)%mod;
w=w*wn%mod;
}
}
}
ll x=finv(len);
if(on==-1) For(i,0,len) F[i]=F[i]*x%mod;
}

void get_inv(ll N,ll* A,ll* B) {
if(N==1) {
B[0]=finv(A[0]);
return;
}
get_inv((N+1)>>1,A,B);
ll n=1;for(;n<=(N<<1);n<<=1);
For(i,0,N-1) X[i]=A[i]; For(i,N,n) X[i]=B[i]=0;
FFT(X,n,1); FFT(B,n,1);
For(i,0,n) B[i]=B[i]*(2-B[i]*X[i]%mod+mod)%mod;
FFT(B,n,-1); For(i,N,n) B[i]=0;
}

int main() {
g[0]=1; For(i,1,n) g[i]=g[i-1]*(ll)i%mod;
get_inv(n+1,g,ginv);
For(i,1,n) h[i]=ginv[i]*(ll)i%mod;
h[0]=1;
get_inv(n+1,h,hinv);
printf("%lld\n",hinv[n]);
return 0;
}


posted @ 2018-06-27 16:07  shixinyi  阅读(317)  评论(0编辑  收藏  举报