zoukankan      html  css  js  c++  java
  • LOJ#6271. 「长乐集训 2017 Day10」生成树求和 加强版

    传送门

    由于是边权三进制不进位的相加,那么可以考虑每一位的贡献
    对于每一位,生成树的边权相当于是做模 (3) 意义下的加法
    考虑最后每一种边权的生成树个数,这个可以直接用生成函数,在矩阵树求解的时候做一遍这个生成函数的模 (3) 意义下的循环卷积求出系数即可
    暴力多项式运算不可取
    考虑选取 (3) 个数字 (x_i),使得 (x_i^3equiv1(mod~10^9+7))
    即找出 (3) 次单位复数根 (omega_3^0,omega_3^1,omega_3^2)
    这个直接带入三角表示法即可得到
    把这些东西带入,矩阵树定理求出点值,最后手动 (DFT^{-1}) 即可

    # include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int mod(1e9 + 7);
    const int inv2((mod + 1) >> 1);
    const int inv3((mod + 1) / 3);
    const int rt3(82062379);
    
    inline int Pow(ll x, int y) {
    	ll ret = 1;
    	for (; y; y >>= 1, x = x * x % mod)
    		if (y & 1) ret = ret * x % mod;
    	return ret;
    }
    
    inline void Inc(int &x, int y) {
    	x = x + y >= mod ? x + y - mod : x + y;
    }
    
    inline void Dec(int &x, int y) {
    	x = x - y < 0 ? x - y + mod : x - y;
    }
    
    inline int Add(int x, int y) {
    	return x + y >= mod ? x + y - mod : x + y;
    }
    
    inline int Sub(int x, int y) {
    	return x - y < 0 ? x - y + mod : x - y;
    }
    
    struct Complex {
    	int a, b;
    
    	inline Complex(int _a = 0, int _b = 0) {
    		a = _a, b = _b;
    	}
    
    	inline Complex operator +(Complex y) const {
    		return Complex(Add(a, y.a), Add(b, y.b));
    	}
    
    	inline Complex operator -(Complex y) const {
    		return Complex(Sub(a, y.a), Sub(b, y.b));
    	}
    
    	inline Complex operator *(Complex y) const {
    		return Complex(Sub((ll)a * y.a % mod, (ll)b * y.b % mod), Add((ll)a * y.b % mod, (ll)b * y.a % mod));
    	}
    
    	inline Complex operator *(int y) const {
    		return Complex((ll)a * y % mod, (ll)b * y % mod);
    	}
    
    	inline Complex operator /(int y) const {
    		int inv = Pow(y, mod - 2);
    		return Complex((ll)a * inv % mod, (ll)b * inv % mod);
    	}
    
    	inline Complex operator /(Complex y) const {
    		return Complex(a, b) * Complex(y.a, mod - y.b) / Add((ll)y.a * y.a % mod, (ll)y.b * y.b % mod);
    	}
    } a[105][105], coef[3], inv, w[3], invw[3];
    
    int n, m, eu[105 * 105], ev[105 * 105], ec[105 * 105], bin[20];
    
    inline Complex Det() {
    	int i, j, k;
    	Complex ret = Complex(1, 0);
    	for (i = 1; i < n; ++i) {
    		for (j = i; j < n; ++j)
    			if (a[j][i].a || a[j][i].b) {
    				if (i == j) break;
    				swap(a[i], a[j]), ret = ret * (mod - 1);
    				break;
    			}
    		for (j = i + 1; j < n; ++j) {
    			inv = a[j][i] / a[i][i];
    			for (k = i; k < n; ++k) a[j][k] = a[j][k] - inv * a[i][k];
    		}
    		ret = ret * a[i][i];
    	}
    	return ret;
    }
    
    inline void IDFT(Complex *p) {
    	int i;
    	Complex tmp[3];
    	tmp[0] = p[0], tmp[1] = p[1], tmp[2] = p[2];
    	p[0] = tmp[0] + tmp[1] + tmp[2];
    	p[1] = tmp[0] + tmp[1] * invw[1] + tmp[2] * invw[2];
    	p[2] = tmp[0] + tmp[1] * invw[2] + tmp[2] * invw[1];
    	for (i = 0; i < 3; ++i) p[i] = p[i] * inv3;
    }
    
    inline int Calc(int p) {
    	int i, j, k;
    	Complex w0, w1, w2, c;
    	for (i = 0; i < 3; ++i) {
    		memset(a, 0, sizeof(a));
    		w0 = Complex(1, 0), w1 = w[i], w2 = w[(i + i) % 3];
    		for (j = 1; j <= m; ++j) {
    			k = ec[j] / bin[p] % 3;
    			c = (k == 1 ? w1 : (k == 2 ? w2 : w0));
    			a[eu[j]][eu[j]] = a[eu[j]][eu[j]] + c;
    			a[ev[j]][ev[j]] = a[ev[j]][ev[j]] + c;
    			a[eu[j]][ev[j]] = a[eu[j]][ev[j]] - c;
    			a[ev[j]][eu[j]] = a[ev[j]][eu[j]] - c;
    		}
    		coef[i] = Det();
    	}
    	IDFT(coef);
    	return (ll)Add(coef[1].a, Add(coef[2].a, coef[2].a)) * bin[p] % mod;
    }
    
    int main() {
    	int i, ans = 0;
    	scanf("%d%d", &n, &m);
    	w[0] = Complex(1, 0), w[1] = Complex(mod - inv2, (ll)rt3 * inv2 % mod);
    	w[2] = Complex(mod - inv2, mod - (ll)rt3 * inv2 % mod);
    	invw[0] = Complex(1, 0) / w[0], invw[1] = Complex(1, 0) / w[1], invw[2] = Complex(1, 0) / w[2];
    	for (i = 1; i <= m; ++i) scanf("%d%d%d", &eu[i], &ev[i], &ec[i]);
    	for (bin[0] = i = 1; i <= 10; ++i) bin[i] = bin[i - 1] * 3;
    	for (i = 0; i <= 10; ++i) Inc(ans, Calc(i));
    	printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    VirtualBox 收缩 vdi镜像文件
    虚拟机安装Lubuntu
    做一个平均数,合计数的sql查询
    postgersql 中 字段名,表名,命名大小写问题(原创)
    你人生中的那口井挖了没有?(转潇湘隐者)
    【智能无线小车系列十一】智能小车一体化测试
    【智能无线小车系列二】车体的组装
    【智能无线小车系列一】物品采购
    【智能无线小车系列十】通过USB摄像头实现网络监控功能
    【智能无线小车系列九】在树莓派上使用USB摄像头
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/10322283.html
Copyright © 2011-2022 走看看