Description
刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.
题解:
好久没写过博客了……
模板题。记
为
的答案,那么有:
大概就是用总方案数减去不合法的,不合法的方案考虑1号点所在的连通块计算方案。
然后移项:
同除
:
然后就可以看做是两个多项式相乘,用求逆求出即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=130010;
const int inf=2147483647;
const int mod=1004535809,g=3;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int Pow(int x,int y)
{
if(y==1)return x;
int t=Pow(x,y>>1),re=(LL)t*t%mod;
if(y&1)re=(LL)re*x%mod;
return re;
}
int bin[Maxn<<2];
void ntt(int *a,int n,int o)
{
bin[0]=0;
for(int i=1;i<n;i++)bin[i]=((bin[i>>1]>>1)|((i&1)*(n>>1)));
for(int i=0;i<n;i++)if(i<bin[i])swap(a[i],a[bin[i]]);
for(int i=1;i<n;i<<=1)
{
int tt;
if(o==1)tt=(mod-1)/(i<<1);
else tt=mod-1-(mod-1)/(i<<1);
int wn=Pow(g,tt);
for(int j=0;j<n;j+=(i<<1))
{
int w=1;
for(int k=0;k<i;k++)
{
int t=(LL)a[i+j+k]*w%mod;w=(LL)w*wn%mod;
a[i+j+k]=(a[j+k]-t+mod)%mod;
a[j+k]=(a[j+k]+t)%mod;
}
}
}
if(o==-1)
{
int t=Pow(n,mod-2);
for(int i=0;i<n;i++)a[i]=(LL)a[i]*t%mod;
}
}
void work(int deg,int *a,int *b,int *tmp)
{
if(deg==1){b[0]=Pow(a[0],mod-2);return;}
work((deg+1)>>1,a,b,tmp);
int m=1;while(m<(deg<<1))m<<=1;
copy(a,a+deg,tmp);fill(tmp+deg,tmp+m,0);
ntt(tmp,m,1),ntt(b,m,1);
for(int i=0;i<m;i++)
{
b[i]=(LL)b[i]*(2-(LL)tmp[i]*b[i]%mod)%mod;
if(b[i]<0)b[i]+=mod;
}
ntt(b,m,-1);fill(b+deg,b+m,0);
}
int a[Maxn<<2],b[Maxn<<2],c[Maxn<<2],d[Maxn<<2];
int n,C[Maxn],fac[Maxn],fin[Maxn],inv[Maxn];
int main()
{
n=read();
C[0]=C[1]=C[2]=1;for(int i=3;i<=n;i++)C[i]=(C[i-1]+i-1)%(mod-1);
fac[0]=1;for(int i=1;i<=n;i++)fac[i]=(LL)fac[i-1]*i%mod;
inv[0]=inv[1]=1;for(int i=2;i<=n;i++)inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
fin[0]=1;for(int i=1;i<=n;i++)fin[i]=(LL)fin[i-1]*inv[i]%mod;
a[0]=a[1]=d[1]=1;d[0]=0;
for(int i=2;i<=n;i++)a[i]=(LL)Pow(2,C[i])*fin[i]%mod;
work(n+1,a,b,c);
for(int i=2;i<=n;i++)d[i]=(LL)Pow(2,C[i])*fin[i-1]%mod;
int m=1;while(m<=(n<<1))m<<=1;
ntt(b,m,1),ntt(d,m,1);
for(int i=0;i<=m;i++)b[i]=(LL)b[i]*d[i]%mod;
ntt(b,m,-1);
printf("%d",(LL)b[n]*fac[n-1]%mod);
}