码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ3456]城市规划

时间:2018-04-04 23:42:27      阅读:378      评论:0      收藏:0      [点我收藏+]

标签:生成   它的   不同   scanf   就是   memset   type   etl   log   

看来我得恶补组合数学了...

先回忆一下指数生成函数乘积的性质:若$\begin{align*}A_e(x)=\sum\limits_{n=0}^\infty a_n\dfrac{x^n}{n!},B_e(x)=\sum\limits_{n=0}^\infty b_n\dfrac{x^n}{n!}\end{align*}$,那么$\begin{align*}A_e(x)B_e(x)=\sum\limits_{n=0}^\infty c_n\dfrac{x^n}{n!}\end{align*}$,其中$\begin{align*}c_n=\sum\limits_{k=0}^n\binom nka_kb_{n-k}\end{align*}$,相当于普通卷积前面多一个组合数的系数

回到本题,设答案为$f_n$,它的指数生成函数为$F(x)$,那么$n![x^n]\dfrac{F^m(x)}{m!}$计数了$n$个带标号点的图被分成$m$个连通块的方案数(先取$m$组点,把它们分别连成连通块,最后消序,在外面乘一个阶乘是为了抵消指数生成函数的阶乘)

对$m$求和,我们就得到了所有不同的图的数量,这个可以直接算:$2^\binom n2$(两两选点,连/不连边),设它的指数生成函数为$G(x)$

于是我们有$\begin{align*}G(x)=\sum\limits_{m=0}^\infty\dfrac{F^m(x)}{m!}=e^{F(x)}\end{align*}$(从$0$开始求和是因为$G(x)$的常数项为$1$,而$\dfrac{F^0(x)}{0!}$刚好也是$1$),也就是$F(x)=\ln G(x)$

多项式求自然对数:给定$G(x)$,求$F(x)=\ln G(x)$

$\begin{align*}F(x)&=\ln G(x)\\F‘(x)&=\dfrac{G‘(x)}{G(x)}\\F(x)&=\int\dfrac{G‘(x)}{G(x)}dx\end{align*}$

所以直接多项式求逆,微分和积分都是$O(n)$的,总时间复杂度$O(n\log_2n)$

#include<stdio.h>
#include<string.h>
const int mod=1004535809;
typedef long long ll;
int mul(int a,int b){return a*(ll)b%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
int rev[300010],N,iN;
int pow(int a,ll b){
	int s=1;
	while(b){
		if(b&1)s=mul(s,a);
		a=mul(a,a);
		b>>=1;
	}
	return s;
}
void pre(int n){
	int i,k;
	for(N=1,k=0;N<n;N<<=1)k++;
	for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
	iN=pow(N,mod-2);
}
void swap(int&a,int&b){a^=b^=a^=b;}
void ntt(int*a,int on){
	int i,j,k,t,w,wn;
	for(i=0;i<N;i++){
		if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(i=2;i<=N;i<<=1){
		wn=pow(3,(on==1)?(mod-1)/i:(mod-1-(mod-1)/i));
		for(j=0;j<N;j+=i){
			w=1;
			for(k=0;k<i>>1;k++){
				t=mul(w,a[i/2+j+k]);
				a[i/2+j+k]=de(a[j+k],t);
				a[j+k]=ad(a[j+k],t);
				w=mul(w,wn);
			}
		}
	}
	if(on==-1){
		for(i=0;i<N;i++)a[i]=mul(a[i],iN);
	}
}
int t0[300010];
void getinv(int*a,int*b,int n){
	if(n==1){
		b[0]=pow(a[0],mod-2);
		return;
	}
	int i;
	getinv(a,b,n>>1);
	pre(n<<1);
	memset(t0,0,sizeof(t0));
	for(i=0;i<n;i++)t0[i]=a[i];
	ntt(t0,1);
	ntt(b,1);
	for(i=0;i<N;i++)b[i]=mul(b[i],de(2,mul(b[i],t0[i])));
	ntt(b,-1);
	for(i=n;i<N;i++)b[i]=0;
}
int t1[300010],t2[300010],inv[300010];
void getln(int*a,int n){
	int i;
	getinv(a,t1,n);
	for(i=1;i<n;i++)t2[i-1]=mul(i,a[i]);
	ntt(t1,1);
	ntt(t2,1);
	for(i=0;i<N;i++)a[i]=mul(t1[i],t2[i]);
	ntt(a,-1);
	for(i=n-1;i>0;i--)a[i]=mul(a[i-1],inv[i]);
	a[0]=0;
	for(i=n;i<N;i++)a[i]=0;
}
#define N 300000
int fac[300010],rfac[300010],a[300010];
int main(){
	int n,i;
	scanf("%d",&n);
	fac[0]=1;
	for(i=1;i<=N;i++)fac[i]=mul(fac[i-1],i);
	rfac[N]=pow(fac[N],mod-2);
	for(i=N;i>0;i--)rfac[i-1]=mul(rfac[i],i);
	for(i=1;i<=N;i++)inv[i]=mul(rfac[i],fac[i-1]);
	for(i=0;i<=n;i++)a[i]=mul(pow(2,i*(ll)(i-1)/2),rfac[i]);
	for(i=1;i<n+1;i<<=1);
	getln(a,i);
	printf("%d",(mul(a[n],fac[n])+mod)%mod);
}

[BZOJ3456]城市规划

标签:生成   它的   不同   scanf   就是   memset   type   etl   log   

原文地址:https://www.cnblogs.com/jefflyy/p/8719344.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!