BZOJ3456 : 城市规划

$a[i]=2^{C_i^2}$

$b[i]=i!$

$c[i]=(i-1)!$

f[i]为i个点的简单无向连通图数目,则有

\[\begin{eqnarray*}f[i]&=&a[i]-\sum_{j=1}^{i-1}C_{i-1}^{j-1}f[j]a[i-j]\\
&=&a[i]-c[i]\sum_{j=1}^{i-1}\frac{f[j]a[i-j]}{c[j]b[i-j]}\end{eqnarray*}\]

$A[i]=\frac{f[i]}{c[i]}$

$B[i]=\frac{a[i]}{b[i]}$

\[\begin{eqnarray*}f[i]=a[i]-c[i]\sum_{j=1}^{i-1}A[j]B[i-j]\end{eqnarray*}\]

右边是个卷积的形式,可以通过分治+NTT在$O(n\log^2n)$复杂度内解决。

 

#include<cstdio>
typedef long long ll;
const int N=131072,K=16;
int n,i,a[N],b[N],c[N],nb[N],nc[N],f[N],A[N],B[N],P=1004535809,g[K+1],ng[K+1],inv[N+1];
inline int pow(int a,ll b){int t=1;for(;b;b>>=1,a=(ll)a*a%P)if(b&1)t=(ll)t*a%P;return t;}
inline void NTT(int*a,int n,int t){
  for(int i=1,j=0;i<n-1;i++){
    for(int s=n;j^=s>>=1,~j&s;);
    if(i<j){int k=a[i];a[i]=a[j];a[j]=k;}
  }
  for(int d=0;(1<<d)<n;d++){
    int m=1<<d,m2=m<<1,_w=t==1?g[d]:ng[d];
    for(int i=0;i<n;i+=m2)for(int w=1,j=0;j<m;j++){
      int&A=a[i+j+m],&B=a[i+j],t=(ll)w*A%P;
      A=(B-t+P)%P;B=(B+t)%P;w=(ll)w*_w%P;
    }
  }
  if(t==-1)for(int i=0,j=inv[n];i<n;i++)a[i]=(ll)a[i]*j%P;
}
void solve(int l,int r){
  if(l==r){f[l]=((a[l]-(ll)c[l]*f[l]%P)%P+P)%P;return;}
  int mid=(l+r)>>1,i,n=r-l+1,k;
  solve(l,mid);
  for(k=1;k<n;k<<=1);
  for(i=0;i<k;i++)A[i]=i+l<=mid?(ll)f[i+l]*nc[i+l]%P:0,B[i]=(ll)a[i]*nb[i]%P;
  NTT(A,k,1),NTT(B,k,1);
  for(i=0;i<k;i++)A[i]=(ll)A[i]*B[i]%P;
  NTT(A,k,-1);
  for(i=r;i>mid;i--)f[i]=(f[i]+A[i-l])%P;
  solve(mid+1,r);
}
int main(){
  for(g[K]=pow(3,(P-1)/N),ng[K]=pow(g[K],P-2),i=K-1;~i;i--)g[i]=(ll)g[i+1]*g[i+1]%P,ng[i]=(ll)ng[i+1]*ng[i+1]%P;
  for(inv[1]=1,i=2;i<=N;i++)inv[i]=(ll)(P-inv[P%i])*(P/i)%P;
  scanf("%d",&n);
  for(b[0]=c[0]=nb[0]=nc[0]=i=1;i<=n;i++){
    a[i]=pow(2,(ll)i*(i-1)/2),b[i]=(ll)b[i-1]*i%P,c[i]=b[i-1];
    nb[i]=pow(b[i],P-2),nc[i]=nb[i-1];
  }
  solve(1,n);
  printf("%d",f[n]);
  return 0;
}

  

posted @ 2015-07-26 21:16  Claris  阅读(412)  评论(0编辑  收藏  举报