1. 程式人生 > >BZOJ3456: 城市規劃

BZOJ3456: 城市規劃

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);
}