数论测试——流浪星球

数论害人不浅啊(虽然这不是一道数论题)

题目描述

描述

前置芝士

gcd

话说 共产党 真的好啊
好吧我还是给个链接就跑
一般来说,我们用的都是辗转相除法

MST

好吧我还是给个链接就跑
附:稀疏图(边数较少的图)或边有序的图一般用 K r u s k a l Kruskal Kruskal,否则用 P r i m Prim Prim

贪心分析

这道题,相当于是一道 最大生成树 。(其实和最小生成树没啥两样,从大到小选边即可)
所以,按照 K r u s k a l Kruskal Kruskal的思想,先把边从大到小选出来就好了啊。

分析

怎么从大到小选边?
如果一个数是另一个数的倍数,那么这两个数的最大公约数就是另外那个数!所以连边尽量就要连有这样关系的边,对每一个数的倍数筛选一下就好。
至于从大到小,因为边权就是被枚举倍数的那个数,所以那个数从大到小枚举即可。

时间复杂度问题

这个就是找倍数,和埃氏筛法很相似,时间复杂度也是相同的,是 O ( n log ⁡ log ⁡ n ) O(n\log\log n) O(nloglogn)看得懂有兴趣的朋友可以看一下证明

代码

#include<map>
#include<set>
#include<list>
#include<queue>
#include<deque>
#include<stack>
#include<ctime>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cctype>
#include<string>
#include<sstream>
#include<fstream>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<iomanip>
#include<iostream>
#include<algorithm>
using namespace std;
#define reg register
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline int getc() { return p1 == p2 && (++p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++; }
//#define getchar getc
template<typename T>
inline T read() {
    T a = 0; char f = 1, c = getchar();
    while(c < '0' || c > '9') {
        if(c == -1) return -1;
        if(c == '-') f = -f;
        c = getchar();
    }
    while('0' <= c && c <= '9') {
        a = (a << 3) + (a << 1) +(c ^ 48);
        c = getchar();
    }
    return a;
}
template<class T>
inline int write(T x) {
    if(x < 0) {
        putchar('-');
        x = (~x) + 1;
    }
    if(x / 10) write(x / 10);
    return putchar(x % 10 | 48);
}
template<class T>
inline int write(T x, char c) {
    return write(x) && putchar(c);
}
inline bool OpenFile() {
    freopen("planet.in", "r", stdin);
    freopen("planet.out", "w", stdout);
    return 1;
}
//bool _Open = OpenFile();
const int MAXN = 200001;
int n = read<int>();
int fa[MAXN];
inline void makeSet(int n) { for(reg int i = 1; i <= n; i++) fa[i] = i; }
inline int findSet(int x) { while(x != fa[x]) x = fa[x] = fa[fa[x]]; return x; }
int x;
long long MST;
int main() {
    makeSet(n);
    for(reg int i = n; i >= 1; i--) {
        for(reg int j = i * 2; j <= n; j += i) {
            int fi = findSet(i), fj = findSet(j);
            if(fi != fj) {
                fa[fi] = fj;
                x++;
                MST += i;
                if(x == n - 1) return !write(MST);
            }
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值