HDU 5552 Bus Routes(2015合肥现场赛A,计数,分治NTT)

题意  给定n个点,任意两点之间可以不连边也可以连边。如果连边的话可以染上m种颜色。

         求最后形成的图,是一个带环连通图的方案数。

 

首先答案是n个点的图减去n个点能形成的树。

n个点能形成的树的方案数比较好求,根据prufer序列可以知道n个点形成的无根树的个数为$n^{n-2}$

那么现在问题变成求n个点形成的连通图的个数。

图有连通和不连通的,那么就是图的总数减去不连通的图的总数。

图的总数很简单,$m^{\frac{n(n-1)}{2}}$,那么现在要求不连通的图的总数。

设$f(n)$为$n$个点的不连通的图的总数

$f(n) = ∑f(i) * C(n - 1, i - 1) * f(n - i)$,$i$从$1$到$n-1$。

这是一个卷积的形式,可以分治NTT来求,就可以了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define	dec(i, a, b)	for (int i(a); i >= (b); --i)
#define	fi		first
#define	se		second
#define	MP		make_pair

typedef long long LL;

const LL G = 106;
const LL mod = 152076289;
const LL N = 4e4 + 10;

int T;
int ca = 0;

LL x1[N], x2[N];
LL ans;
LL n, m;
LL f[N], g[N], h[N];
LL c[N], fac[N], ifac[N];

LL Pow(LL a, LL b){  
	LL ret = 1;  
	while (b){  
		if (b & 1) ret = (ret * a) % mod;  
		a = (a * a) % mod;  
		b >>= 1;  
	}  
	return ret;  
}  

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

void ntt (LL *y, int len, int on) {
	change (y, len);
	int id = 0;
	for(int h = 2; h <= len; h <<= 1) {
		id++;
		LL wn = Pow (G, (mod - 1) / (1<<id));
		for(int j = 0; j < len; j += h) {
			LL w = 1;
			for(int k = j; k < j + h / 2; k++) {
				LL u = y[k] % mod;
				LL T = w * (y[k + h / 2] % mod) % mod;
				y[k] = (u + T) % mod;
				y[k + h / 2] = ((u - T) % mod + mod) % mod;
				w = w * wn % mod;
			}
		}
	}
	if (on == -1){
		for (int i = 1; i < len / 2; i++)
			swap (y[i], y[len - i]);
		LL inv = Pow(len, mod - 2);
		for(int i = 0; i < len; i++)
			y[i] = y[i] % mod * inv % mod;
	}
}

void solve(int l, int r){
	if (l == r){
		f[l] += g[l];
		f[l] %= mod;
		return;
	}

	int mid = (l + r) >> 1;
	solve(l, mid);
	int len = 1;
	while (len <= r - l + 1) len <<= 1;
	rep(i, 0, len - 1) x1[i] = x2[i] = 0;

	rep(i, l, mid)   x1[i - l] = f[i] * ifac[i - 1] % mod;
	rep(i, 1, r - l) x2[i - 1] = g[i] * ifac[i] % mod;

	ntt(x1, len, 1);
	ntt(x2, len, 1);
	rep(i, 0, len - 1) x1[i] = x1[i] * x2[i] % mod;
	ntt(x1, len, -1);
	rep(i, mid + 1, r){
		f[i] -= x1[i - l - 1] % mod * fac[i - 1] %mod;
		(f[i] += mod) %= mod;
	}
	solve(mid + 1, r);
}

int main(){

	fac[0] = 1;
	rep(i, 1, N - 1) fac[i] = fac[i - 1] * i % mod;
	ifac[N - 1] = Pow(fac[N - 1], mod - 2);
	dec(i, N - 2, 0) ifac[i] = ifac[i + 1] * (i + 1) % mod;

	scanf("%d", &T);
	while (T--){
		scanf("%lld%lld", &n, &m);
		memset(f, 0, sizeof f);
		rep(i, 1, n) g[i] = Pow(m + 1, 1ll * i * (i - 1) / 2);
		solve(1, n);
		ans = (f[n] - Pow(n, n - 2) * Pow(m, n - 1) % mod + mod) % mod; 
		printf ("Case #%d: %lld\n", ++ca, ans);
	}

	return 0;
}

  

 

posted @ 2018-10-17 16:20  cxhscst2  阅读(340)  评论(0编辑  收藏  举报