ABC 210 E - Ring MST

E - Ring MST

数论,最小生成树

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

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

    \(0,d,2d,3d...\)

    \(1,d+1,2d+1...\)

    \(2,d+2,2d+2...\)

    ...

    这些点联通,留下 \(0,1,2,...,d-1\) 这些点为代表的连通块

  3. 所以可将这 \(m\) 个操作的代价从小到大排序,每种操作可以将 \(n\) 个连通块变为 \(d\) 个连通块,代价为 \((n-d)*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 @ 2022-06-10 17:01  hzy0227  阅读(67)  评论(0编辑  收藏  举报