3456: 城市规划

3456: 城市规划

Time Limit: 40 Sec   Memory Limit: 256 MB
Submit: 475   Solved: 273
[ 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

Source

[ Submit][ Status][ Discuss]

题解戳这里


搞了有点久啊。。GG
对于多项式求逆,,写的时候细节没注意
一个n次多项式的逆一定也是一个n次多项式,当递归处理长度为len的逆时应自动舍去后面的原式(因为这个时候已经被模掉了)。。
然后公式要注意边界和多项式乘法的运算法则,这里卡了有点久。。GG
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 1<<18;
typedef long long LL;
const LL mo = 1004535809;

int n,N,L,rev[maxn],Num[maxn]; 
LL g[maxn],inv[maxn],C[maxn],fac[maxn],F[maxn]
   ,G[maxn],b[maxn],c[maxn];

LL ksm(LL x,LL y)
{
	LL ret = 1;
	for (; y; y >>= 1LL) {
		if (y&1LL) ret = ret*x%mo;
		x = x*x%mo;
	}
	return ret;
}

void Pre_Work()
{
	LL tot = 1,sum = 2; 
	C[0] = C[1] = 1;
	for (int i = 2; i <= n; i++) {
		tot = tot*sum%mo;
		sum = 2LL*sum%mo;
		C[i] = tot;
	}
	fac[0] = 1;
	for (int i = 1; i <= n; i++) 
		fac[i] = 1LL*i*fac[i-1]%mo;
	inv[n] = ksm(fac[n],mo-2);
	for (int i = n - 1; i >= 0; i--)
		inv[i] = 1LL*(i+1)*inv[i+1]%mo;
	g[0] = g[N] = 1;
	g[1] = ksm(3,(mo-1)/N);
	for (int i = 2; i < N; i++)
		g[i] = g[i-1]*g[1]%mo;
}

void Rader(LL *a,int len)
{
	int j = len>>1;
	for (int i = 1; i < len - 1; i++) {
		if (i < j) swap(a[i],a[j]);
		int k = len>>1;
		while (j >= k) {
			j -= k;
			k >>= 1;
		}
		j += k;
	}
	
}

void NTT(LL *a,int len,int on)
{
	Rader(a,len);
	for (int k = 2; k <= len; k <<= 1) 
		for (int i = 0; i < len; i += k) {
			int pos = 0;
			for (int j = i; j < i + (k>>1); j++) {
				LL u = a[j];
				LL w = g[pos]*a[j+(k>>1)]%mo;
				a[j] = (u+w)%mo;
				a[j+(k>>1)] = (u-w+mo)%mo;
				pos += (N/k);
			}
		}
	if (on == -1) {
		LL INV = ksm(len,mo-2);
		for (int i = 0; i < len; i++)
			a[i] *= INV,a[i] %= mo;
	}
}

void Rev()
{
	for (int i = 0; i <= (N>>1); i++)
		swap(g[i],g[N-i]);
}

void Inv(int deg,int len)
{
	if (deg == 1) {
		b[0] = ksm(G[0],mo-2);
		return;
	}
	Inv((deg+1)>>1,len>>1);
	for (int i = 0; i < deg; i++) c[i] = G[i];
	for (int i = deg; i < len; i++) c[i] = 0;
	NTT(b,len,1);
	NTT(c,len,1);
	for (int i = 0; i < len; i++) 
		b[i] = (2LL - c[i]*b[i]%mo + mo)*b[i]%mo;
	Rev(); 
	NTT(b,len,-1); Rev();
	for (int i = deg; i < N; i++) b[i] = 0;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n;
	for (N = 1; N <= n; N <<= 1,++L);
	N <<= 1; ++L; 
	Pre_Work();
	for (int i = 0; i < n; i++) 
		G[i] = C[i]*inv[i]%mo;
	Inv(n+1,N);
	for (int i = 1; i <= n; i++)
		F[i] = C[i]*inv[i-1]%mo;
	NTT(b,N,1); NTT(F,N,1);
	for (int i = 0; i < N; i++)
		F[i] = b[i]*F[i]%mo;
	Rev(); NTT(F,N,-1);
	cout << F[n]*fac[n-1]%mo;
	return 0;
}

你可能感兴趣的:(NTT)