• 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
    ", ++ca, ans);
    	}
    
    	return 0;
    }
    

      

  • 相关阅读:
    <q>标签,短文本引用
    使用<span>标签为文字设置单独样式
    html速查表
    禁用第三方键盘
    画虚线的方法 (记录)
    渐变色以及隐藏输入框光标
    iOS9 网络适配
    iOS 截屏/将图片存储到相册或沙盒目录下
    从任意字符串中获取所有的数字
    IOS开发
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/9804908.html
Copyright © 2020-2023  润新知