BZOJ3456: 城市規劃
阿新 • • 發佈:2018-11-25
BZOJ3456: 城市規劃
https://lydsy.com/JudgeOnline/problem.php?id=3456
分析:
- 設\(f[n]\)表示\(n\)個點的答案, \(g[n]\)表示總方案數。
- 列舉和\(1\)連通的點的個數, \(f[n]=g[n]-\sum\limits_{i=1}^{n-1}\binom{n-1}{i-1}f(i)g(n-i)\)。
- 然後把式子劃開就是一個多項式求逆了
程式碼:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define mod 1004535809 #define N 400050 typedef long long ll; int qp(int x,ll y) { int re=1; for(;y;y>>=1,x=ll(x)*x%mod) if(y&1) re=ll(re)*x%mod; return re; } #define INV(x) (qp(x,mod-2)) void ntt(int *a,int len,int flg) { int i,j,k,t,w,wn,tmp; for(i=k=0;i<len;i++) { if(i>k) swap(a[i],a[k]); for(j=len>>1;(k^=j)<j;j>>=1) ; } for(k=2;k<=len;k<<=1) { t=k>>1; wn=qp(3,(mod-1)/k); if(flg==-1) wn=INV(wn); for(i=0;i<len;i+=k) { w=1; for(j=i;j<i+t;j++) { tmp=ll(a[j+t])*w%mod; a[j+t]=(a[j]-tmp)%mod; a[j]=(a[j]+tmp)%mod; w=ll(w)*wn%mod; } } } if(flg==-1) { t=INV(len); for(i=0;i<len;i++) a[i]=ll(a[i])*t%mod; } } int A[N],B[N],F[N],G[N],H[N],fac[N],inv[N],n,g[N]; void get_inv(int *a,int *b,int len) { if(len==1) { b[0]=INV(a[0]); return ; } get_inv(a,b,len>>1); int t=len<<1,i; for(i=0;i<len;i++) A[i]=a[i],B[i]=b[i]; ntt(A,t,1), ntt(B,t,1); for(i=0;i<t;i++) B[i]=(2-ll(A[i])*B[i])%mod*B[i]%mod; ntt(B,t,-1); for(i=0;i<len;i++) b[i]=B[i]; } int main() { scanf("%d",&n); int i; for(fac[0]=i=1;i<=n;i++) fac[i]=ll(fac[i-1])*i%mod; for(i=1;i<=n;i++) { g[i]=qp(2,ll(i)*(i-1)/2); } inv[n]=INV(fac[n]); for(i=n-1;i>=0;i--) inv[i]=ll(inv[i+1])*(i+1)%mod; H[0]=1; for(i=1;i<=n;i++) { H[i]=ll(g[i])*inv[i]%mod; G[i]=ll(g[i])*inv[i-1]%mod; } int len=1; while(len<=n) len<<=1; get_inv(H,F,len); len<<=1; ntt(F,len,1), ntt(G,len,1); for(i=0;i<len;i++) F[i]=ll(F[i])*G[i]%mod; ntt(F,len,-1); printf("%lld\n",(ll(F[n])*fac[n-1]%mod+mod)%mod); }