1 条题解
-
0
自动搬运
来自洛谷,原作者为

Doubeecat
关注 LLM4OI 谢谢喵搬运于
2025-08-24 22:36:56,当前版本为作者最后更新于2022-03-16 16:09:17,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
给定一个点编号在 范围内的完全图,边 的权值为 ,请你求出这张图的最小生成树权值和。
解题思路:
Kruskal 优化建图。
观察到如果直接建图的时间复杂度是 的,无法接受。但是发现在这个过程中,有很多边实际上是可以省略的,接下来来发掘一下这些边的性质。
首先我们有
$$\mathrm{lcm}(u, v) = \frac{u\times v}{\mathrm{gcd}(u,v)} $$这实际上启发了我们从 的角度进行思考,我们发现,如果将两个有共同因子的点连边,这条边的权值是较小的。观察到 ,这启发我们去枚举这个因子。同时我们发现,如果对于一个因子 来说,在 里的数都满足 这样的形式,显然对于 及后面的数,向 连边是最优秀的,这样我们对于一个因子最多建边数量为 的。
而我们可以枚举因子,因子的范围是 ,最后我们建边的数量就应该是 $\lfloor\frac{R-L}{2}\rfloor + \lfloor\frac{R-L}{3}\rfloor + \dots + \lfloor\frac{R-L}{R}\rfloor$ 根据调和级数,这个东西的边数是 的,实际上这个上界很松,具体数据会更小,极限数据大概是 左右的,建出边后跑 Kruskal 就过了。
时间复杂度 。
代码:
const int N = 1e6 + 10; int l,r,f[N],buc[N]; bool vis[N]; ll gcd(ll a,ll b) { return !b ? a : gcd(b,a%b); } ll lcm(ll a,ll b) { return a / gcd(a,b) * b; } int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);} struct node { int l,r; ll w; friend inline bool operator < (const node &a,const node &b) { return a.w < b.w; } }; vector <node> edge; void Kruskal() { sort(edge.begin(),edge.end()); int cnt = 0; ll ans = 0; for (auto e : edge) { int x = e.l,y = e.r;ll w = e.w; if (find(x) != find(y)) { //printf("%d %d %lld\n",x,y,w); f[max(find(x),find(y))] = min(find(x),find(y)); ans += w; } } printf("%lld\n",ans); } signed main() { read(l,r); ll ans = 0; for (int i = l;i <= r;++i) f[i] = i,buc[i] = 1; for (int i = 2;i <= r;++i) { //if (vis[i]) continue; int cnt = 0,fis = 0; for (int j = i;j <= r;j += i) { if (buc[j] && !fis) fis = j; if (buc[j]) edge.push_back((node){fis,j,lcm(fis,j)}); vis[j] = 1; } if (i >= l) edge.push_back((node){fis,l,lcm(fis,l)}); } Kruskal(); return 0; }
- 1
信息
- ID
- 7562
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者