ABC 210 E - Ring MST

E - Ring MST

数论,最小生成树

  1. 根据 kruskal 的原理,将边排序取最小的、可以两端点未联通的前 n1 条边即可,但本题的边数是 nm 级别,不能排序

  2. 只有 m 种操作,每种操作的代价是相同的,第 i 种操作是连接 x(x+Ai)modn ,根据数论的知识,设 d=gcd(n,Ai), 则这种操作最多将

    0,d,2d,3d...

    1,d+1,2d+1...

    2,d+2,2d+2...

    ...

    这些点联通,留下 0,1,2,...,d1 这些点为代表的连通块

  3. 所以可将这 m 个操作的代价从小到大排序,每种操作可以将 n 个连通块变为 d 个连通块,代价为 (nd)c

    n=1 时则图已联通

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 1e5 + 10;
int n, m;
int gcd(int a, int b)
{
	if (b == 0)
		return a;
	return gcd(b, a % b);
}

struct Node
{
	int a;
	ll c;
	bool operator<(const Node &x) const
	{
		return c < x.c;
	}
}op[N];

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++)
		cin >> op[i].a >> op[i].c;
	sort(op + 1, op + m + 1);
	ll ans = 0;
	int cnt = 0;
	for (int i = 1; i <= m; i++)
	{
		auto [a, c] = op[i];
		int d = gcd(a, n);
		ans += (n - d) * c;
		n = d;
		if (n == 1)
			break;
	}
	cout << (n == 1 ? ans : -1) << endl;
    return 0;
}
posted @   hzy0227  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示