【bzoj3456】 城市规划

题目

一句话题意,无向连通图计数

技不如人,甘拜下风

\(f_i\)表示\(i\)个节点构成的无向连通图数量

之后。。。之后就不会了

于是抄题解

考虑容斥

\[f_i=t_i-\sum_{j=1}^{i-1}\binom{i-1}{j-1}f_jt_{i-j} \]

\(t_i\)表示\(i\)个节点构成的无向图数量,实际上\(t_i=2^{\frac{i(i-1)}{2}}\),就是每一条边都有存在或者不存在两种选择,这样显然不能保证联通

上面那个柿子的含义就是先算上所有情况,减掉不连通的,先选择\(j-1\)个点和\(1\)号节点联通,之后剩下的\(i-j\)个节点自己随便连去吧,由于两部分没有联通,所以整张图一定不会联通

我们觉得让\(f_i\)在外面孤独的待着不太好,于是我们可以把\(f_i\)放进来

就有

\[t_i-\sum_{j=1}^n\binom{i-1}{j-1}f_jt_{i-j} \]

因为当\(j=i\)的时候,\(\binom{i-1}{j-1}=t_{i-j}=1\),所以可以把\(f_i\)放进来

拆组合数

\[t_i=\sum_{j=1}^n\frac{(i-1)!f_jt_{i-j}}{(j-1)!(i-j)!} \]

\((i-1)!\)真多余,让它出来

\[\frac{t_i}{(i-1)!}=\sum_{j=1}^n\frac{f_j}{(j-1)!}\times \frac{t_{i-j}}{(i-j)!} \]

考虑生成函数,设

\[G(x)=\frac{t_x}{(x-1)!},F(x)=\frac{f_i}{(i-1)!},T(x)=\frac{t_x}{x!} \]

于是我们直观发现应该写成

\[G(x)=F(x) \times T(x) \]

于是\(F(x)=\frac{G(x)}{T(x)}\),多项式求逆就好了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
const int maxn=262144+1005;
const LL mod=1004535809;
LL G[2];
LL K[maxn],T[maxn],C[maxn];
LL fac[maxn],t[maxn],pow[maxn],A[maxn],R[maxn],B[maxn],ifac[maxn];
int rev[maxn],n,len;
inline LL ksm(LL a,LL b) {LL S=1;while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}return S;}
inline void NTT(LL *f,int o) {
	for(re int i=0;i<len;i++) if(i<rev[i]) std::swap(f[i],f[rev[i]]);
	for(re int i=2;i<=len;i<<=1) {
		int ln=i>>1;LL og1=ksm(G[o],(mod-1)/i);
		for(re int l=0;l<len;l+=i) {
			LL t,og=1;
			for(re int x=l;x<l+ln;x++) {
				t=(og*f[ln+x])%mod;
				f[ln+x]=(f[x]-t+mod)%mod;
				f[x]=(f[x]+t)%mod;
				og=(og*og1)%mod;
			}
		}
	}
	if(!o) return;
	LL inv=ksm(len,mod-2);
	for(re int i=0;i<len;i++) f[i]=(f[i]*inv)%mod;
}
inline void mul(int n,LL *A,LL *B) {
	len=1;while(len<n+n) len<<=1;
	for(re int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|((i&1)?len>>1:0);
	NTT(A,0),NTT(B,0);for(re int i=0;i<len;i++) A[i]=(A[i]*B[i])%mod;
	NTT(A,1);for(re int i=n;i<len;i++) A[i]=0;
}
inline void Inv(int n,LL *A,LL *B) {
	if(n==1) {B[0]=ksm(A[0],mod-2);return;}
	Inv((n+1)>>1,A,B);
	memset(C,0,sizeof(C));memset(T,0,sizeof(T));memset(K,0,sizeof(K));
	for(re int i=0;i<n;i++) C[i]=K[i]=B[i],T[i]=A[i];
	mul(n,C,K);mul(n,C,T);
	for(re int i=0;i<n;i++) B[i]=(2ll*B[i]-C[i]+mod)%mod;
}
int main() {
	G[0]=3,G[1]=ksm(3,mod-2);
	scanf("%d",&n);
	pow[0]=1;for(re int i=1;i<=n;i++) pow[i]=(pow[i-1]*2ll)%mod;
	fac[0]=1;for(re int i=1;i<=n;i++) fac[i]=(fac[i-1]*(LL)i)%mod;
	t[0]=1;t[1]=1;for(re int i=2;i<=n;i++) t[i]=(t[i-1]*pow[i-1])%mod;
	ifac[n]=ksm(fac[n],mod-2);
	for(re int i=n-1;i>=0;--i) ifac[i]=(ifac[i+1]*(LL)(i+1))%mod;
	for(re int i=0;i<=n;i++) B[i]=t[i]*ifac[i]%mod;
	for(re int i=1;i<=n;i++) A[i]=t[i]*ifac[i-1]%mod;
	Inv(n+1,B,R);mul(n+1,A,R);
	printf("%lld\n",A[n]*fac[n-1]%mod);
	return 0;
}
posted @ 2019-03-18 08:47  asuldb  阅读(210)  评论(0编辑  收藏  举报