題目大意
求出有n个点的有标号简单连通无向图的数目。
题解
什么破玩意,直接输出(2^{C_n^2})走人
我们发现这张图要求连通,而上式肯定不能保证连通。
其实上式表示的是不保证连通的有标号简单无向图。
就差在一个连通上啊。
所以我们设(f(x))表示有x个点的有标号简单连通无向图的数目。
然后设(g(x))为上式,即不保证连通时的方案数
于是我们枚举节点1所在的连通块的大小,有
[g(n) = sum_{i=1}^nC_{n-1}^{i-1}f(i)g(n-1)
]
即
[frac{g(n)}{(n-1)!} = frac{sum_{i=1}^nC_{n-1}^{i-1}f(i)g(n-1)}{(n-1)!}
]
[frac{2^{C_n^2}}{(n-1)!} = sum_{i=1}{n}frac{f(i)}{(i-1)!}frac{2^{C_{n-i}^2}}{(n-i)!}
]
那么我们分别设它们的生成函数为
[A(x) = sum_{n=1}^{infty}frac{f(n)}{(n-1)!}x^n
]
[B(x) = sum_{n=0}^{infty}frac{2^{C_n^2}}{n!}x^n
]
[C(x) = sum_{n=0}^{infty}frac{2^{C_n^2}}{(n-1)!}x^n
]
所以我们有
[C(x) = A(x)B(x)
]
那么有
[A(x) equiv B^{-1}(x)C(x) (mod ext{ }x^{n+1})
]
所以利用FFT算逆元,处理乘法即可.
//这里用的FNT,即快速数论变换.
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 1 << 18;
const int mod = 1004535809;
const int pri_rt = 3;
inline int qpow(int x,int p){
int ret = 1;
for(;p;x=1LL*x*x%mod,p>>=1) if(p&1) ret=1LL*ret*x%mod;
return ret;
}
int len;
int e[maxn],ie[maxn];
inline int check(int &x){
if(x < 0) x += mod;
if(x >= mod) x -= mod;
}
inline void init(){
int bas = qpow(pri_rt,(mod-1)/len);
int inv = qpow(bas,mod-2);
e[0] = ie[0] = 1;
for(int i=1;i<len;++i){
e[i] = 1LL*e[i-1]*bas % mod;
ie[i] = 1LL*ie[i-1]*inv % mod;
}
}
void FNT(int n,int *x,int *w){
for(int i=0,t=0;i<n;++i){
if(i > t) swap(x[i],x[t]);
for(int j=n>>1;(t^=j) < j;j>>=1);
}
for(int m=2;m<=n;m<<=1){
int k = m>>1,wn = len/m;
for(int i=0;i<n;i+=m){
for(int j=0,p=0;j<k;++j,p+=wn){
int u = 1LL*x[i+j+k]*w[p] % mod;
x[i+j+k] = x[i+j] - u;check(x[i+j+k]);
x[i+j] = x[i+j] + u;check(x[i+j]);
}
}
}
if(w == ie){
int inv = qpow(n,mod-2);
for(int i=0;i<n;++i) x[i] = 1LL*x[i]*inv%mod;
}
}
struct Node{
int n;
int x[maxn];
Node(){n = x[0] = 0;}
};
void get_inv(int n,const Node &A,Node &B){
if(n == 1){
B.n = 1;
B.x[0] = qpow(A.x[0],mod-2);
return;
}
static int X[maxn];
get_inv((n+1)>>1,A,B);
int p = 1;for(;p < n<<1 ;p<<=1);
copy(A.x,A.x+n,X);fill(X+n,X+p,0);
fill(B.x+B.n,B.x+p,0);
FNT(p,X,e);FNT(p,B.x,e);
for(int i=0;i<p;++i) B.x[i] = 1LL*B.x[i]*(2 - 1LL*X[i]*B.x[i] % mod) % mod;
FNT(p,B.x,ie);B.n = n;
}
Node A,B,C;
int inv[maxn],inv_fac[maxn],c[maxn];
int main(){
int n;read(n);
int p;for(p=1;p<(n+1)<<1;p<<=1);
len = p;init();
inv[1] = inv_fac[0] = 1;
for(int i=1;i<=n;++i){
if(i != 1) inv[i] = -mod/i*(ll)inv[mod % i] % mod;
if(inv[i] < 0) inv[i] += mod;
inv_fac[i] = (ll)inv_fac[i-1]*inv[i]%mod;
}
c[0] = c[1] = 1;
for(int i=2;i<=n;++i) c[i] = qpow(2,(ll)i*(i-1)/2 % (mod - 1));
A.n = B.n = n+1;
for(int i=0;i<=n;++i) A.x[i] = (ll)c[i]*inv_fac[i] % mod;
for(int i=1;i<=n;++i) B.x[i] = (ll)c[i]*inv_fac[i-1]%mod;
get_inv(n+1,A,C);
fill(C.x + C.n,C.x + p,0);
FNT(p,C.x,e);FNT(p,B.x,e);
for(int i=0;i<=p;++i) C.x[i] = (ll)C.x[i]*B.x[i] % mod;
FNT(p,C.x,ie);
int ans = (ll)C.x[n]*qpow(inv_fac[n-1],mod - 2) % mod;
if(ans < 0) ans += mod;
printf("%d
",ans);
getchar();getchar();
return 0;
}