您的位置:首页 > 其它

BZOJ 3456: 城市规划 多项式求逆/分治NTT

2018-02-24 14:47 363 查看

3456: 城市规划

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 1003  Solved: 579
[Submit][Status][Discuss]

Description

 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
 好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
 由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.

Input

 仅一行一个整数n(<=130000) 

Output

 仅一行一个整数, 为方案数 mod 1004535809. 

Sample Input

3

Sample Output

4

HINT

 对于 100%的数据, n <= 130000

首先呢可以用 POJ 1737: Connected Graph 组合数学 高精度 的解法
之后分治NTT一下 O(nlog^2n)

也可以考虑容斥
之后化完式子 发现要求的在卷积里
所以就多项式求逆一发就好了
多项式求逆看这里↓
多项式求逆

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

typedef double db;
typedef long long ll;

inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=10*x+ch-'0';ch=getchar();}
return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=400100,mod=1004535809;

inline int qpow(int x,int y)
{
int res(1);
while(y)
{
if(y&1) res=1ll*res*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return res;
}

int n;

int fac
,inv
,E
;

void initial()
{
register int i;
fac[0]=1;for(i=1;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod;
inv[1]=1;for(i=2;i<=n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
inv[0]=1;for(i=1;i<=n;++i) inv[i]=1ll*inv[i]*inv[i-1]%mod;
E[0]=1;E[1]=1;for(i=2;i<=n;++i) E[i]=qpow(2,(1ll*i*(i-1)>>1)%(mod-1));
}

int r
;

void ntt(int *x,int lim,int opt)
{
register int i,j,k,m,gn,g,tmp;
for(i=0;i<lim;++i)
if(r[i]<i)
swap(x[i],x[r[i]]);
for(m=2;m<=lim;m<<=1)
{
k=m>>1;
gn=qpow(3,(mod-1)/m);
for(i=0;i<lim;i+=m)
{
g=1;
for(j=0;j<k;++j,g=1ll*g*gn%mod)
{
tmp=1ll*x[i+j+k]*g%mod;
x[i+j+k]=(x[i+j]-tmp+mod)%mod;
x[i+j]=(x[i+j]+tmp)%mod;
}
}
}
if(opt==-1)
{
reverse(x+1,x+lim);
int inv(qpow(lim,mod-2));
for(i=0;i<lim;++i) x[i]=1ll*x[i]*inv%mod;
}
}

int B
,C
,D
,S
,T
;

void get_inv(int deg)
{
if(deg==1)
{
D[0]=qpow(B[0],mod-2);
return ;
}
get_inv((deg>>1)+(deg&1));

int lim(1);
while(lim<(deg<<1)) lim<<=1;
for(int i=0;i<lim;++i)
T[i]=0,
r[i]=(i&1)*(lim>>1)+(r[i>>1]>>1);

for(int i=0;i<deg;++i) T[i]=B[i];
ntt(T,lim,1);ntt(D,lim,1);
for(int i=0;i<lim;++i)
D[i]=((D[i]<<1)%mod-1ll*T[i]*D[i]%mod*D[i]%mod+mod)%mod;
ntt(D,lim,-1);
for(int i=deg;i<lim;++i) D[i]=0;
}

int main()
{
n=read();
initial();
register int i,lim(1);
for(i=0;i<=n;++i) B[i]=1ll*E[i]*inv[i]%mod;
for(i=1;i<=n;++i) C[i]=1ll*E[i]*inv[i-1]%mod;
get_inv(n+1);
while(lim<=(n<<1)) lim<<=1;
ntt(C,lim,1);ntt(D,lim,1);
for(i=0;i<lim;++i) C[i]=1ll*C[i]*D[i]%mod;
ntt(C,lim,-1);
cout<<1ll*C
*fac[n-1]%mod<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: