【BZOJ1016】【Luogu P4208】 [JSOI2008]最小生成树计数 最小生成树,矩阵树定理
蛮不错的一道题,遗憾就遗憾在数据范围会导致暴力轻松跑过。
最小生成树的两个性质:
不同的最小生成树,相同权值使用的边数一定相同。
不同的最小生成树,将其都去掉同一个权值的所有边,其连通性一致。
这样我们随便跑一个\(MST\),就可以知道所有\(MST\)边的构造情况。由于性质二,我们可以考虑枚举每一种权值的所有边,保留所有非此权值的树边,看可以连出来多少种不同的最小生成树。也就是按照权值构造最小生成树,这个过程满足乘法原理。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100 + 5;
const int M = 1000 + 5;
const int Mod = 31011;
struct Len {
int u, v, w;
bool operator < (Len rhs) const {
return w < rhs.w;
}
}l[M];
vector <Len> v;
int n, m, S[N];
int find (int x) {
return S[x] == x ? x : S[x] = find (S[x]);
}
vector <int> val, use, tot;
vector <int> :: iterator it;
void kruskal () {
sort (l + 1, l + 1 + m);
for (int i = 0; i <= n; ++i) S[i] = i;
for (int i = 1; i <= m; ++i) {
int fu = find (l[i].u);
int fv = find (l[i].v);
it = lower_bound (val.begin (), val.end (), l[i].w);
if (it == val.end ()) {
val.push_back (l[i].w);
use.push_back (0);
tot.push_back (1);
} else {
tot[it - val.begin ()]++;
}
if (fu != fv) {
S[fu] = fv;
it = lower_bound (val.begin (), val.end (), l[i].w);
use[it - val.begin ()]++;
v.push_back (l[i]);
}
}
}
int mat[N][N];
int gauss (int n) {
int ret = 1;
for (int i = 1; i <= n; ++i) {
for (int k = i + 1; k <= n; ++k) {
while (mat[k][i]) {
int d = mat[i][i] / mat[k][i];
for (int j = i; j <= n; ++j) {
(((mat[i][j] -= d * mat[k][j]) %= Mod) += Mod) %= Mod;
}
swap (mat[i], mat[k]); ret = -ret;
}
}
(((ret *= mat[i][i]) %= Mod) += Mod) %= Mod;
}
return abs (ret);
}
void add_edge (int u, int v) {
mat[u][u]++;
mat[v][v]++;
mat[u][v]--;
mat[v][u]--;
}
int sep[N];
int solve () {
kruskal ();
if (v.size () < n - 1) return 0;
int ans = 1;
for (int i = 0; i < val.size (); ++i) {
memset (mat, 0, sizeof (mat));
if (use[i] == 0 || tot[i] == use[i]) continue;
for (int j = 0; j <= n; ++j) S[j] = j;
for (int j = 0; j < v.size (); ++j) {
if (v[j].w != val[i]) {
S[find (v[j].u)] = find (v[j].v);
}
}
int cnt = 0;
for (int i = 1; i <= n; ++i) {
sep[++cnt] = find (i);
}
sort (sep + 1, sep + 1 + cnt);
cnt = unique (sep + 1, sep + 1 + cnt) - sep - 1;
for (int j = 1; j <= m; ++j) {
if (l[j].w == val[i]) {
int fu = find (l[j].u);
int fv = find (l[j].v);
fu = lower_bound (sep + 1, sep + 1 + cnt, fu) - sep;
fv = lower_bound (sep + 1, sep + 1 + cnt, fv) - sep;
add_edge (fu, fv);
}
}
(ans *= gauss (use[i])) %= Mod;
}
return ans;
}
signed main () {
// freopen ("data.in", "r", stdin);
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
static int u, v, w;
cin >> u >> v >> w;
l[i] = (Len) {u, v, w};
}
cout << solve () << endl;
}
【BZOJ1016】【Luogu P4208】 [JSOI2008]最小生成树计数 最小生成树,矩阵树定理的更多相关文章
- bzoj1016 [JSOI2008]最小生成树计数——Kruskal+矩阵树定理
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016 从 Kruskal 算法的过程来考虑产生多种方案的原因,就是边权相同的边有一样的功能, ...
- BZOJ 1016 最小生成树计数(矩阵树定理)
我们把边从小到大排序,然后依次插入一种权值的边,然后把每一个联通块合并. 然后当一次插入的边不止一条时做矩阵树定理就行了.算出有多少种生成树就行了. 剩下的交给乘法原理. 实现一不小心就会让程序变得很 ...
- 洛谷4208 JSOI2008最小生成树计数(矩阵树定理+高斯消元)
qwq 这个题目真的是很好的一个题啊 qwq 其实一开始想这个题,肯定是无从下手. 首先,我们会发现,对于无向图的一个最小生成树来说,只有当存在一些边与内部的某些边权值相同的时候且能等效替代的时候,才 ...
- 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)
1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...
- [spoj104][Highways] (生成树计数+矩阵树定理+高斯消元)
In some countries building highways takes a lot of time... Maybe that's because there are many possi ...
- spoj104 highways 生成树计数(矩阵树定理)
https://blog.csdn.net/zhaoruixiang1111/article/details/79185927 为了学一个矩阵树定理 从行列式开始学(就当提前学线代了.. 论文生成树的 ...
- @总结 - 7@ 生成树计数 —— matrix - tree 定理(矩阵树定理)与 prüfer 序列
目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 矩阵树定理主体@ @证明 part - 1@ @证明 part - 2@ @证明 part - 3@ @证明 part ...
- 【Luogu】P3317重建(高斯消元+矩阵树定理)
题目链接 因为这个专门跑去学了矩阵树定理和高斯消元qwq 不过不是很懂.所以这里只放题解 玫葵之蝶的题解 某未知dalao的矩阵树定理 代码 #include<cstdio> #inclu ...
- Luogu P4336 [SHOI2016]黑暗前的幻想乡 矩阵树定理+容斥原理
真是菜到爆炸....容斥写反(反正第一次写qwq) 题意:$n-1$个公司,每个公司可以连一些边,求每个边让不同公司连的生成树方案数. 矩阵树定理+容斥原理(注意到$n$不是很大) 枚举公司参与与否的 ...
- 【BZOJ4596】【Luogu P4336】 [SHOI2016]黑暗前的幻想乡 矩阵树定理,容斥
同样是矩阵树定理的裸题.但是要解决它需要能够想到容斥才可以. \(20\)以内的数据范围一定要试试容斥的想法. #include <bits/stdc++.h> using namespa ...
随机推荐
- Android逆向——破解水果大战
最近公司需要测试安卓app安全,但安卓基本上0基础,决定开始学习下安卓逆向根据吾爱破解上教程 <教我兄弟学Android逆向系列课程+附件导航帖> https://www.52pojie. ...
- HNU_团队项目_Android和数据库对接出现问题总结
1. 问题说明:Android发来的数据JSON格式不对,Time和Date的位置相反 出现原因:Android的JSON数据组装时顺序不对(可能) 2.问题说明:Android发来的数据无法插入到数 ...
- PJzhang:URL重定向漏洞的72般变化
猫宁!!! 反射型xss的利用可以给对方发送钓鱼链接,窃取对方cookie,进入对方账户. 利用url重定向漏洞,发送给对方一个钓鱼链接,重定向到一个恶意网页,比如一个假的银行网站,被盗取账号密码 ...
- mybatis批量更新update-设置多个字段值allowMultiQueries=true
mybatis由于简单易用性得到大家的认可和使用 但是在批量更新操作中,网上介绍的貌似不全,正好今天做个记录,大家一起进步 在实际项目开发过程中,常有这样的需求:根据ids更新表的某一个字段值,这时的 ...
- 牛客小白月赛14 -A (找规律+除数取模)
题目链接:https://ac.nowcoder.com/acm/contest/879/A 题意:有n个城市,编号1~n,k天,第一天位于城市1,要求最后一天在城市1,且相邻两天不在同一个城市,求方 ...
- sql server不同排序规则的数据库间字段的比较
不同的排序规则的字段是不能直接比较的.会提示:无法解决 equal to 操作的排序规则冲突.可以把字段强制转换一个排序规则,这样就能比较了.示例: ------------------------- ...
- 云数据库 MongoDB版
阿里云云数据库MongoDB版是一种安全可靠.可弹性伸缩的云数据库服务,目前支持ReplicaSet和Sharding两种部署架构,通过简单的几步操作即可快速部署.阿里云云数据库MongoDB版是一种 ...
- 终于搞懂了vue 的 render 函数(一) -_-|||
终于搞懂了vue 的 render 函数(一) -_-|||:https://blog.csdn.net/sansan_7957/article/details/83014838 render: h ...
- # C++中对PI的引用
#include <iostream> #include <cmath> using namespace std; int main(){ printf("%.10l ...
- layui2.5 修改layuicms
雷哥layui2.5版本学习 学习地址: https://www.bilibili.com/video/av59813890/?p=30 注意: 修改layuicms时注意下面是缓存的js, < ...