zoukankan      html  css  js  c++  java
  • luoguP4208 [JSOI2008]最小生成树计数 矩阵树定理

    题目大意:

    求最小生成树的数量


    曾今的我感觉这题十分的不可做

    然而今天看了看,好像是个类模板的题....

    我们十分容易知道,记能出现在最小生成树中的边的集合为(S)

    那么,只要是(S)中的边构成的树,一定能构成最小生成树

    我们只要预处理哪些可能在最小生成树中即可

    打个树剖维护以下就可以了

    太懒了,不想打太长,然后就拿并查集随便弄了弄

    最后来个矩阵树就行了

    (31011)不是一个质数,用辗转相除法来消元

    复杂度(O(n^3 log n))


    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define ri register int
    #define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
    #define drep(io, ed, st) for(ri io = ed; io >= st; io --)
    
    const int sid = 105;
    const int mod = 31011;
    inline void inc(int &a, int b) { a += b; if(a >= mod) a -= mod; }
    inline void dec(int &a, int b) { a -= b; if(a < 0) a += mod; }
    inline int mul(int a, int b) { return 1ll * a * b % mod; }
    	
    int n, m, fa[sid];
    int E[sid][sid];
    struct edge {
    	int u, v, w;
    	friend bool operator < (edge a, edge b)
    	{ return a.w < b.w; }
    } e[sid * 10];
    
    inline int find(int o) {
    	if(o == fa[o]) return o;
    	else return fa[o] = find(fa[o]);
    }
    
    inline void init() {
    	sort(e + 1, e + m + 1);
    	rep(i, 1, n) fa[i] = i;
    	for(ri i = 1, j; i <= m; i = j + 1) {
    		j = i; 
    		while(e[j].w == e[i].w) j ++; j --;
    		rep(k, i, j) {
    			int u = find(e[k].u), v = find(e[k].v);
    			if(u == v) continue;
    			inc(E[u][u], 1); inc(E[v][v], 1);
    			inc(E[u][v], mod - 1); inc(E[v][u], mod - 1);
    		}
    		rep(k, i, j) {
    			int u = find(e[k].u), v = find(e[k].v);
    			if(u == v) continue; fa[u] = v;
    		}
    	}
    }
    
    inline void calc() {
    	int sign = 1;
    	n --;
    	rep(i, 1, n) rep(j, i + 1, n)
    		while(E[j][i]) {
    			int t = E[i][i] / E[j][i];
    			rep(k, i, n)  dec(E[i][k], mul(t, E[j][k]));
    			swap(E[j], E[i]);
    			sign *= -1;
    		}
    	int ans = 1;
    	rep(i, 1, n) ans = mul(ans, E[i][i]);
    	if(sign == 1) printf("%d
    ", ans);
    	else printf("%d
    ", mod - ans);
    }
    
    int main() {
    	cin >> n >> m;
    	for(int i = 1; i <= m; i ++)
    		cin >> e[i].u >> e[i].v >> e[i].w;
    	init(); calc();
    	return 0;
    }
    
  • 相关阅读:
    回文链表
    istringstream
    编写函数,以读模式打开一个文件,将其内容读入到一个string的vector中,将每一行作为一个对立的元素存于vector中
    c++ primer,友元函数上的一个例子(By Sybase)
    类的静态成员
    聚合类和字面值常量类
    隐式的类类型转换
    构造函数
    类的作用域
    类的其他特性
  • 原文地址:https://www.cnblogs.com/reverymoon/p/10139149.html
Copyright © 2011-2022 走看看