嘘~ 正在从服务器偷取页面 . . .

ABC210E Ring MST 题解


ABC210E Ring MST 题解

题目链接:ABC210E Ring MST

题意:给定一张 $n$ 个点的无向图,顶点的编号为 $0,1,\dots,n−1$ 。同时给出两个长度为 $m$ 的数组 $a_1,a_2,\dots,a_m$ 和 $b_1,b_2,\dots,b_m$ 。初始时图中并没有任何边,你可以按照以下操作加边:

选择一个 $1\le i\le m$ 和一个 $0<x<n$ ,并在顶点 $x$ 和顶点 $(x+a_i) \bmod n$ 中添加一条长度为 $b_i$ 的边。

你现在想要知道,你添加的边的长度总和至少为多少,才能使得整个图连通?如果无论如何都不能使整个图连通,输出 $−1$ 。

数据范围:

$1 \le a_i < n \le 10^9,~1 \le m \le 10^5,1\le b_i \le 10^9$

首先我们可以想到把 $(x,(x+a_i)\bmod n)$ 看作一条边

然后答案就是最小生成树,跑个 $\text{kruskal}$

不过这个是 $O(nm)$ 的,这是不能接受的

于是我们模拟 $\text{kruskal}$ 的算法过程,不过更加快捷

把 $(a_i,b_i)$ 按 $b_i$ 排序升序排序,保证有 $\forall i < j,~b_i\le b_j$

然后考虑尽可能的用较前的 $(a_i,b_i)$ 来建边

有一个结论:令 $g=\gcd(a_i,n)$ ,

所有模 $g$ 相同的结点均可以连到同一个连通块,并且会有 $g$ 个这样的连通块

注:此时我们尽可能在用 $a_i$ 建边,这里连到同一个连通块就是指尽可能建边的结果

这个结论其实证起来很简单

方便起见,我们固定 $0$ 为起点,显然这不会影响答案

则只用 $a_i$ 从 $0$ 可以走到的点一定是

其中 $x,y \in \mathbb{Z}$ 。

令 $c=a_ix+ny$ ,根据裴蜀定理可知,如果有解,则 $g \mid c$

注意我们这里是 $c$ ,实际上我们还会从 $0,1,\dots,g-1$ 出发去连边

不难发现这样我们会连出 $g$ 个这样的连通块

然后我们试着去推广这个结论

如果我们用前 $i$ 个 $a_i$ ,则他们一共有 $g=\gcd(a_1,a_2,\dots,a_i,n)$ 个连通块

详细证明我也不太会,但是这个就是个很显然的结论

不难发现,当 $g=1$ 时,图就联通了。

然后这题就没了。边权只要用 $\sum(g_{i-1}-g_{i}) \times b_{i}$ 来算就行啦

这题我在Roundgod老师的指导下想了一个小时左右才想明白 QAQ

时间复杂度 $O(m\log m)$

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define F first
#define S second
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)()
typedef pair<int,int> P;
int n,m;
vector<P> vec;
int gcd(int a,int b)
{return b==0?a:gcd(b,a%b);}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m; vec.clear();
    for(int i=1,u,v; i<=m; i++)
    {
        cin >> u >> v;
        vec.push_back({v,u});
    }
    sort(vec.begin(),vec.end());
    int ans=0,g=n;
    for(int i=0; i<m; i++)
    {
        int tmp=g;
        g=gcd(g,vec[i].S);
        ans+=(tmp-g)*vec[i].F;
    }
    if(g!=1) cout << "-1\n";
    else cout << ans << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录