题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=3456
题解
个点构成的连通图数量为
枚举号点所在连通块的大小,得到
因此
整理得到
令
则有
即
先求出和,求的逆元,卷积一遍就可以得到,得到之后很容易得到。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=300000;
const int mod=1004535809;
const int G=3;
int quickpow(int a,int b,int m)
{
int res=1;
while(b)
{
if(b&1)
{
res=1ll*res*a%m;
}
a=1ll*a*a%m;
b>>=1;
}
return res;
}
int plus(int a,int b,int m)
{
int res=a+b;
if(res>=m)
{
res-=m;
}
return res;
}
int minus(int a,int b,int m)
{
int res=a-b;
if(res<0)
{
res+=m;
}
return res;
}
int rev[maxn+10],tmp[maxn+10];
int getrev(int n)
{
int m=1,len=0;
while(m<=n)
{
m<<=1;
++len;
}
for(int i=0; i<m; ++i)
{
rev[i]=(rev[i>>1]>>1)+((i&1)<<(len-1));
}
return m;
}
int fft(int *s,int len)
{
for(int i=0; i<len; ++i)
{
if(rev[i]<i)
{
std::swap(s[rev[i]],s[i]);
}
}
for(int i=2; i<=len; i<<=1)
{
int gn=quickpow(G,(mod-1)/i,mod);
for(int j=0; j<len; j+=i)
{
int g=1;
for(int k=0; k<(i>>1); ++k)
{
int x=s[j+k],y=1ll*g*s[j+k+(i>>1)]%mod;
s[j+k]=plus(x,y,mod);
s[j+k+(i>>1)]=minus(x,y,mod);
g=1ll*g*gn%mod;
}
}
}
return 0;
}
int getinv(int *s,int *v,int deg)
{
if(deg==1)
{
v[0]=quickpow(s[0],mod-2,mod);
return 0;
}
getinv(s,v,(deg+1)>>1);
int p=getrev(deg<<1);
for(int i=0; i<deg; ++i)
{
tmp[i]=s[i];
}
for(int i=deg; i<p; ++i)
{
tmp[i]=0;
}
fft(tmp,p);
fft(v,p);
for(int i=0; i<p; ++i)
{
v[i]=1ll*v[i]*minus(2,1ll*tmp[i]*v[i]%mod,mod)%mod;
}
fft(v,p);
std::reverse(v+1,v+p);
int fk=quickpow(p,mod-2,mod);
for(int i=0; i<p; ++i)
{
v[i]=1ll*v[i]*fk%mod;
}
for(int i=deg; i<p; ++i)
{
v[i]=0;
}
return 0;
}
int n,g[maxn+10],t[maxn+10],fac[maxn+10],ig[maxn+10],ifac[maxn+10];
int main()
{
n=read();
fac[0]=1;
for(int i=1; i<=n; ++i)
{
fac[i]=1ll*i*fac[i-1]%mod;
}
ifac[n]=quickpow(fac[n],mod-2,mod);
for(int i=n-1; i; --i)
{
ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
}
ifac[0]=1;
for(int i=1; i<=n; ++i)
{
int v=quickpow(2,((1ll*(i-1)*i)/2)%(mod-1),mod);
g[i]=1ll*v*ifac[i]%mod;
t[i]=1ll*v*ifac[i-1]%mod;
}
g[0]=1;
getinv(g,ig,n+1);
int m=getrev(n<<1);
fft(t,m);
fft(ig,m);
for(int i=0; i<m; ++i)
{
g[i]=1ll*t[i]*ig[i]%mod;
}
fft(g,m);
std::reverse(g+1,g+m);
int fk=quickpow(m,mod-2,mod);
for(int i=0; i<m; ++i)
{
g[i]=1ll*g[i]*fk%mod;
}
printf("%lld\n",1ll*g[n]*fac[n-1]%mod);
return 0;
}