首页 > 其他分享 >P2143 [JSOI2010] 巨额奖金 题解

P2143 [JSOI2010] 巨额奖金 题解

时间:2024-04-02 15:22:06浏览次数:10  
标签:JSOI2010 return P2143 fa int 题解 ++ lap mod

P2143 [JSOI2010] 巨额奖金 题解

矩阵树定理+Kruskal

最小生成树计数。

思路

MST 都是喵喵题。

引理 1:所有合法的权值相同边的连边方案,得到的连通块情况是相同的。

感性理解:如果不相同意味着至少有一条边可以连通一对连通块。

所以我们可以这么做:先跑 Kruskal 标记树边,然后枚举边权,对于同一边权的树边先删掉,所有剩余的图用并查集缩点,之后加入当前边权的边,缩点后图的生成树个数就是当前边权边的放置方案,根据引理,每个边权贡献独立,所以乘法原理即可。

注意每次要把所有的非当前边权的树边加入,否则可能导致图不连通。

时间复杂度:\(O(n^3)\)。

// Problem: P4208 [JSOI2008] 最小生成树计数
// Author: Moyou
// Copyright (c) 2024 Moyou All rights reserved.
// Date: 2024-04-02 13:29:52

#include <algorithm>
#include <iostream>
#include <map>
#define int long long
using namespace std;
const int N = 200 + 10, mod = 31011;

int n, m, lap[N][N], fa[N];
struct qwq {
    int u, v, w;
} e[1010];
int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);}
void merge(int a, int b) {
    int x = find(a), y = find(b);
    if(x == y) return ;
    fa[x] = y;
}
int tot;
map<int, int> h;
int id(int x) {
    if(h.count(x)) return h[x];
    return h[x] = ++ tot;
}
void add(int a, int b) {
    lap[a][a] ++, lap[b][b] ++, lap[a][b] --, lap[b][a] --;
}
int det(int n) {
    int c = 1;
    for(int i = 1; i < n; i ++)
        for(int j = i + 1; j < n; j ++)
            while(lap[j][i]) {
                int d = lap[i][i] / lap[j][i];
                for(int k = i; k < n && d; k ++)
                    lap[i][k] = (lap[i][k] - 1ll * d * lap[j][k] % mod) % mod;
                swap(lap[i], lap[j]), c = -c;
            }
    for(int i = 1; i < n; i ++) c = 1ll * c * lap[i][i] % mod;
    return (c + mod) % mod;
}
void clear() {
    for(int i = 1; i <= tot; i ++)
        for(int j = 1; j <= tot; j ++)
            lap[i][j] = 0;
    tot = 0; h.clear();
}
bool ok[1010];
void kruskal() {
    for(int i = 1; i <= n; i ++) fa[i] = i;
    for(int i = 1; i <= m; i ++) {
        int x = find(e[i].u), y = find(e[i].v);
        if(x != y) fa[x] = y, ok[i] = 1;
    }
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for(int i = 1; i <= m; i ++)
        cin >> e[i].u >> e[i].v >> e[i].w;
    sort(e + 1, e + m + 1, [](qwq a, qwq b) {return a.w < b.w;});
    int ans = 1;
    kruskal();
    for(int i = 1, j = 0; i <= m; i = j + 1) {
        clear();
        for(int i = 1; i <= n; i ++) fa[i] = i;
        j = i;
        while(j < m && e[j + 1].w == e[i].w) j ++;
        for(int k = 1; k < i; k ++) if(ok[k]) merge(e[k].u, e[k].v);
        for(int k = j + 1; k <= m; k ++) if(ok[k]) merge(e[k].u, e[k].v);
        for(int k = i; k <= j; k ++) {
            int x = find(e[k].u), y = find(e[k].v);
            if(x != y) add(id(x), id(y));
        }
        for(int k = i; k <= j; k ++)
            merge(e[k].u, e[k].v);
        ans = 1ll * ans * det(tot) % mod;
    }
    for(int i = 1; i < n; i ++) if(find(i) != find(i + 1)) return cout << 0, 0;
    cout << ans << '\n';

    return 0;
}

标签:JSOI2010,return,P2143,fa,int,题解,++,lap,mod
From: https://www.cnblogs.com/MoyouSayuki/p/18110654

相关文章

  • P1967 [NOIP2013 提高组] 货车运输 题解
    P1967[NOIP2013提高组]货车运输原题地址思路:由于题目要求的是使两点之间的最小边权最大,所以可以构造最大生成树(最大生成树一定是最大瓶颈生成树,而瓶颈生成树上两点之间的路径,在原图中的所有路径中,最小边权仍然最大,即满足题目要求,详见https://oi-wiki.org/graph/mst/#性质),......
  • Golang | Leetcode Golang题解之第4题寻找两个正序数组的中位数
    题目:题解:funcfindMedianSortedArrays(nums1[]int,nums2[]int)float64{iflen(nums1)>len(nums2){returnfindMedianSortedArrays(nums2,nums1)}m,n:=len(nums1),len(nums2)left,right:=0,mmedian1,median2:=0,0......
  • CF1935D Exam in MAC 题解
    ExaminMAC题意\(t\)组数据。给定一个大小为\(n\)的集合\(s\)和一个整数\(c\),保证\(0\leqslants_i\leqslantc(1\leqslanti\leqslantn)\)。求有多少对整数数对\((x,y)\),满足:\(0\leqslantx\leqslanty\leqslantc\)。\(x+y\notins\)且\(y-x\not......
  • 2024最新一线互联网大厂常见高并发面试题解析
    面试官:临界区是什么?答:临界区用来表示一种公共资源或者说是共享资源,可以被多个线程使用。但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程要想使用这个资源,就必须等待。比如,在一个办公室里有一台打印机,打印机一次只能执行一个任务。如果小王和小明同时需要打......
  • 【赛题解析】【移动应用开发】全国职业院校技能大赛任务一:实现社区首页功能解析
    ​培训、环境、资料、考证公众号:波比网络公众号2:波比网络工作室移动应用开发技能大赛交流群:548238632波比网络专注于技能提升,赋能**本文章全文由波比网络原创,非法转载必究!**文章目录移动应用与开发任务1:实现社区首页功能1.界面顶部显示所在社区名称、轮播图和社......
  • IDEA中新建SpringBoot模块,JDK版本问题解决
    问题描述IDEA中新建SpringBoot模块,使用的JAVAJDK1.8,新建模块时选项中没有JDK8: 运行时报错,JDK之类的问题解决方案,查看修改以下四个地方:(1)设置-Java编译器 (2)项目结构--依赖以及源码 ......
  • 哈尔滨理工大学3-31校赛模拟赛第一场题解
    概览:ABF为签到题,CE模拟,D深搜,G最短路,H双指针A.提取数字:注意前导零的情况需要排除,由于组成的数不超过longlong范围,所以直接用res承接就好了#include<iostream>usingnamespacestd;longlongres;intmain(){charc;while(cin>>c)if(c>='0'&&c<='9......
  • CCF CSP模拟真题解答示例
    CCFCSP(CertifiedSoftwareProfessional)是中国计算机学会主办的软件能力认证考试,旨在评估参赛者在计算机科学和软件工程方面的基本知识和实践能力。请注意,以下解答仅作为示例,并非针对实际真题的准确答案。实际考试中的题目和答案可能会有所不同,因此建议参考官方发布的真题......
  • 洛谷 P9907 [COCI 2023/2024 #1] Mostovi 题解
    题目分析首先可以确定的是需要枚举断边,所以我们希望两次枚举之间能有些关联。不难想到类树形DP的套路,建DFS树,只不过这题除了讨论和父亲之间的边,还要考虑返租边。以下钦定以\(1\)为树根。树边先从简单的树边开始考虑。考虑不经过\(u\)和\(u\)的父亲\(v\),对答案是否产......
  • ABC347F 题解
    我们考虑这三个正方形的相对位置有多少种情况。我们把正方形的顶点设为\((x_i,y_i)\)。容易发现,放置合法当且仅当\(\foralli\neqj,|\x_i-x_j\|\geqd\\text{or}|\y_i-y_j\|\geqd\)。发现这只有可能是以下两种情况。于是便可以开始写了。/***********......