题意:
求n个点的简单无向图个数。
题解:
n2
容斥是个经典套路:
f[x]=2C2x−∑i=1n−1Ci−1n−1∗f[i]∗2C2n−i
2C2x=∑i=1nCi−1n−1∗f[i]∗2C2n−i
两边除 (n−1)!
2C2x(n−1)!=∑i=1nf[i](i−1)!∗2C2n−i(n−i)!
于是这个函数成了卷积形式:
C(x)=F(x)G(x)
F(x)=C(x)∗G(x)−1 (mod xn+1)
求逆即可。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
LL a[520010],b[520010],c[520010],t[520010];
LL f[130010],inv[130010],C[130010];
LL p=1004535809,g=3,bin[520010];
LL pow(LL a,LL b,LL mod)
{
LL ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
a=a*a%p;b>>=1;
}
return ans;
}
void ntt(LL *a,LL n,LL op)
{
for(LL i=0;i<n;i++) bin[i]=(bin[i>>1]>>1)|((i&1)*(n>>1));
for(LL i=0;i<n;i++) if(i<bin[i]) swap(a[i],a[bin[i]]);
for(LL i=1;i<n;i<<=1)
{
LL wn=pow((LL)g,op==1?(p-1)/(2*i):p-1-(p-1)/(2*i),p),w,t;
for(LL j=0;j<n;j+=i<<1)
{
w=1;
for(LL k=0;k<i;k++)
{
t=w*a[i+j+k]%p;w=w*wn%p;
a[i+j+k]=(a[j+k]-t+p)%p;a[j+k]=(a[j+k]+t)%p;
}
}
}
if(op==-1)
{
LL Inv=pow(n,p-2,p);
for(LL i=0;i<n;i++) a[i]=a[i]*Inv%p;
}
}
void pol_inv(LL deg,LL *a,LL *b,LL *tmp)
{
//printf("%d\n",deg);
if(deg==1) {b[0]=pow(a[0],p-2,p);return;}
pol_inv((deg+1)>>1,a,b,tmp);
LL n=1;while(n<deg<<1) n<<=1;
copy(a,a+deg,tmp);fill(tmp+deg,tmp+n,0);
ntt(tmp,n,1);ntt(b,n,1);
for(LL i=0;i<n;i++)
{
b[i]=(2-tmp[i]*b[i]%p)*b[i]%p;
if(b[i]<0) b[i]+=p;
}
ntt(b,n,-1);fill(b+deg,b+n,0);
}
LL n,k;
int main()
{
scanf("%lld",&n);
k=1;while(k<(n+1)<<1) k<<=1;
f[0]=f[1]=inv[0]=inv[1]=C[0]=C[1]=1;
for(LL i=2;i<=n;i++) f[i]=f[i-1]*i%p,inv[i]=(LL)(p-p/i)*inv[p%i]%p;
for(LL i=2;i<=n;i++) inv[i]=inv[i]*inv[i-1]%p;
for(LL i=2;i<=n;i++) C[i]=pow(2LL,(LL)i*(i-1)/2%(p-1),p);
for(LL i=0;i<=n;i++) a[i]=C[i]*inv[i]%p;
for(LL i=1;i<=n;i++) b[i]=C[i]*inv[i-1]%p;
pol_inv(n+1,a,c,t);
//for(int i=0;i<=n;i++) printf("%lld ",c[i]);printf("\n");
//for(int i=0;i<=n;i++) printf("%lld ",b[i]);printf("\n");
ntt(b,k,1);ntt(c,k,1);//printf("ok\n");
for(LL i=0;i<k;i++) c[i]=c[i]*b[i]%p;ntt(c,k,-1);
printf("%lld",c[n]*f[n-1]%p);
}