1 条题解
-
0
#include<bits/stdc++.h> using namespace std; // [1] 全局常量:最大数值限制,适配题目B≤100000的范围 const int MAXN = 100010; // [2] 全局数组:并查集父节点数组,存储每个整数的父节点编号 int fa[MAXN]; // [3] 全局数组:并查集深度数组,用于按秩合并优化 int dep[MAXN]; // [4] 全局数组:埃氏筛标记数组,标记每个数是否为质数 bool is_prime[MAXN]; // [5] 全局数组:存储筛出的所有质数 vector<int> primes; // [6] 全局数组:标记根节点是否已被统计,避免栈溢出 bool vis[MAXN]; // 函数声明 void sieve(int maxn); int find(int x); void unite(int x, int y); // [7] 主函数:程序运行入口 int main() { int A, B, P; cin >> A >> B >> P; // [8] 读入整数范围A、B,以及公共质因数阈值P // [9] 调用sieve函数筛出MAXN以内的所有质数,跳转至该函数完成注释 sieve(MAXN - 1); // [17] 回到主函数,筛质数完成 // [18] 循环初始化并查集,为每个整数初始化集合状态 for(int i = 0; i < MAXN; i++) { fa[i] = i; // [19] 每个整数初始独立为一个集合,父节点设为自身 dep[i] = 1; // [20] 每个集合的初始树深度设为1 vis[i] = false; // [21] 初始化标记数组为false } // [22] 遍历所有筛出的质数,处理符合条件的质数 for(int p : primes) { if(p < P || p > B) continue; // [23] 跳过小于P或大于B的质数,不满足合并条件 // [24] 计算当前质数p在[A,B]范围内的第一个倍数 int first = ((A + p - 1) / p) * p; // 向上取整计算第一个>=A的p的倍数 if(first > B) continue; // [25] 范围内无该质数的倍数,跳过 // [26] 循环遍历该质数的所有倍数,合并到同一个集合 for(int j = first + p; j <= B; j += p) { // [27] 调用unite函数合并当前倍数和第一个倍数,跳转至该函数完成注释 unite(first, j); } } // [39] 回到主函数,所有合并操作完成 int setCnt = 0; // [40] 统计变量:记录最终的集合数量 // [41] 循环遍历[A,B]范围内的所有整数,统计集合数量 for(int i = A; i <= B; i++) { // [42] 调用已注释的find函数,获取当前整数的根节点 int root = find(i); if(!vis[root]) // [43] 根节点未被统计过 { setCnt++; // [44] 集合计数+1 vis[root] = true; // [45] 标记该根节点已统计 } } cout << setCnt << endl; // [46] 输出最终的集合数量 return 0; // [47] 主函数正常结束 } // [10] 跳转至sieve函数:埃氏筛法,筛出maxn以内的所有质数,修复溢出问题 void sieve(int maxn) { // [11] 函数参数maxn:筛数的上限 memset(is_prime, true, sizeof is_prime); // [12] 初始化所有数标记为质数 is_prime[0] = is_prime[1] = false; // [13] 0和1不是质数,标记为false // [14] 循环筛除合数,修复整数溢出问题 for(int i = 2; i <= maxn; i++) { if(is_prime[i]) // [15] 若当前数是质数 { primes.push_back(i); // 加入质数列表 // 修复:j从i*2开始,彻底避免i*i溢出问题 for(int j = i * 2; j <= maxn; j += i) { is_prime[j] = false; } } } } // [16] sieve函数注释完成,返回主函数继续注释 // [28] 跳转至find函数:带路径压缩,查找节点x所在集合的根节点 int find(int x) { // [29] 函数参数x:待查找根节点的整数 if(x != fa[x]) { fa[x] = find(fa[x]); // [30] 路径压缩:直接将当前节点指向根节点,优化查询效率 } return fa[x]; // [31] 返回找到的根节点 } // [32] find函数注释完成,返回unite函数继续注释 // [33] 跳转至unite函数:按秩合并x和y所在的两个集合 void unite(int x, int y) { // [34] 函数参数x、y:待合并的两个整数 x = find(x); // [35] 查找x的根节点 y = find(y); // [36] 查找y的根节点 if(x == y) return; // [37] 两数已属于同一集合,无需重复合并 // [38] 按秩合并逻辑:将深度更小的树合并到深度更大的树下,保持树结构平衡 if(dep[x] > dep[y]) { fa[y] = x; } else if(dep[x] < dep[y]) { fa[x] = y; } else { fa[y] = x; dep[x]++; // 两棵树深度相同时,合并后根节点深度+1 } } // [39] unite函数注释完成,返回主函数继续注释
- 1
信息
- ID
- 1366
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者