Luogu P4841 城市规划

求n个点的无向连通图数量 f ( n ) f(n) f(n)
可以发现,n个点的无向图数量 g ( n ) g(n) g(n) f ( n ) f(n) f(n)这两个函数有着如下关系:
g ( n ) n ! = ∑ i = 1 n f i i ! = e f \frac {g(n)}{n!} = \sum_{i=1}^n \frac {f^{i}}{i!} = e^{f} n!g(n)=i=1ni!fi=ef
然后对 g g g l n ln ln就行了。

AC Code:

#include<bits/stdc++.h>
#define maxn 280000
#define LL long long
#define mod 1004535809
using namespace std;

int lg[maxn],inv[maxn]={1,1},invf[maxn]={1,1},fac[maxn]={1,1},r[maxn],w[maxn]={1},wlen;
template<class T>int Pow(int base,T k)
{	int ret=1;
	for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll*ret*base%mod;
	return ret;
}
void Init(int n)
{	for(wlen=1;n>=(wlen<<1);wlen<<=1);
	for(int i=1,pw=Pow(3,(mod-1)/(wlen<<1));i<=2*wlen;i++) w[i] = 1ll * w[i-1] * pw % mod;
	for(int i=2;i<=2*wlen;i++) 
		lg[i]=lg[i>>1]+1,inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod,
		fac[i]=1ll*fac[i-1]*i%mod,invf[i]=1ll*invf[i-1]*inv[i]%mod; }
inline void NTT(int *A,int n,int tp)
{	int lgn = lg[n];
	for(int i=1;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(lgn-1));
	for(int i=1;i<n;i++) if(i<r[i]) swap(A[i],A[r[i]]);
	for(int L=2;L<=n;L<<=1)
		for(int st=0,l=L>>1,inc=wlen/l;st<n;st+=L)
			for(int k=st,x=0;k<st+l;k++,x+=inc)
			{	int tmp = 1ll*(tp==1?w[x]:w[2*wlen-x])*A[k+l]%mod;
				A[k+l]=(A[k]-tmp)%mod,A[k]=(A[k]+tmp)%mod;}
	if(tp==-1)for(int i=0,inv=Pow(n,mod-2);i<n;i++) A[i]=1ll*A[i]*inv%mod;}
void Inv(int *A,int *B,int n)
{	B[0]=Pow(A[0],mod-2);
	static int tmp[maxn];
	for(int k=2;k<(n<<1);k<<=1)
	{	for(int i=0,lim=min(n,k);i<(k<<1);i++) tmp[i]=i<lim?A[i]:0,B[i]=i<lim?B[i]:0;
		NTT(tmp,k<<1,1),NTT(B,k<<1,1);
		for(int i=0;i<(k<<1);i++) B[i]=1ll*B[i]*(2-1ll*B[i]*tmp[i]%mod)%mod;
		NTT(B,k<<1,-1);for(int i=min(n,k);i<(k<<1);i++) B[i]=0;}}
void cLn(int *A,int *B,int n)
{	Inv(A,B,n);
	static int tmp[maxn];
	int lgn = lg[n-1]+2 , len = 1<<lgn;
	for(int i=0;i<len;i++) tmp[i]=i<n-1?1ll*A[i+1]*(i+1)%mod:0;
	NTT(tmp,len,1),NTT(B,len,1);
	for(int i=0;i<len;i++) tmp[i]=1ll*tmp[i]*B[i]%mod;
	NTT(tmp,len,-1);B[0]=0;
	for(int i=1;i<n;i++) B[i]=1ll*tmp[i-1]*inv[i]%mod;
	for(int i=n;i<len;i++) B[i] = 0;}
int a[maxn],b[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	Init((n+10)<<1);
	for(int i=0;i<=n;i++) a[i]=1ll*invf[i]*Pow(2,1ll*(i-1)*i/2)%mod;
	cLn(a,b,n+1);
	printf("%lld\n",(1ll*b[n]*fac[n]%mod+mod)%mod);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值