1 条题解
-
0
题解说明
问题描述:
给定多个查询,每次输入两个整数 和 。需要根据特定规则计算一个值:- 如果 ,答案为
- 否则设 ,提取 中的 的因子,记为
- 如果 不能被 整除,答案为
- 否则答案为 的约数个数
因此问题的核心是:快速求任意数的约数个数,并在查询时高效计算 。
核心思路:
预处理约数个数:- 使用线性筛法(Euler 筛)预处理 的约数个数 。
- 对于质数 ,。
- 对于合数 ,若 与 互质,则 ;
若 是 的质因子,则需修正:
。
查询处理:
- 输入 ,若相等直接返回 。
- 保证 ,计算 。
- 将 中的 因子全部提取出来,记录 。
- 若 ,返回 。
- 否则计算 ,答案为 。
输出:
- 每个查询独立处理,输出对应答案。
算法流程:
调用 ,用线性筛预处理 。
输入查询次数 。
对每个查询:- 读入
- 按规则计算答案
- 输出结果
复杂度分析:
- 预处理: 时间,,线性筛可行。
- 每次查询:
- 计算
- 常数操作
- 总复杂度:,其中 为查询数, 为输入数值范围。
实现细节与注意点:
- 特殊处理。
- 线性筛时,注意合数的约数个数计算需要区分是否含有相同质因子。
- 使用内置函数 。
- 输入输出使用 fast IO,避免超时。
总结:
该代码通过“线性筛预处理约数个数 结合因子分解”的方式,实现了对每个查询#include <bits/stdc++.h> using namespace std; // 定义最大范围,根据题目需求设置 #define N 10000005 // 快速读入函数,提高输入效率 int read() { int w = 0, f = 1; char c = ' '; // 处理正负号 while (c < '0' || c > '9') c = getchar(), f = c == '-' ? -1 : f; // 读取数字部分 while (c >= '0' && c <= '9') w = w * 10 + c - 48, c = getchar(); return w * f; } // 全局变量 int pri[N / 10]; // 存储质数 int vis[N]; // 标记非质数,同时存储最小质因子 int d[N]; // 存储每个数的约数个数 int cnt; // 质数计数器 // 处理单个查询 int solve() { int x = read(), y = read(); // 若两数相等,直接返回0 if (x == y) return 0; // 保证x < y if (x > y) swap(x, y); int z = y - x, tmp = 1; // 提取z中所有的因子2,tmp记录2的幂次 while (!(z & 1)) z >>= 1, tmp <<= 1; // 若x不能被tmp整除,返回0 if (x % tmp) return 0; // 计算gcd并返回其约数个数 return d[__gcd(z, x / tmp)]; } // 初始化函数:预处理约数个数 void init() { d[1] = 1; // 1的约数只有1个 // 线性筛法预处理 for (int i = 2; i < N; i++) { if (!vis[i]) { // i是质数 pri[++cnt] = i; d[i] = 2; // 质数有2个约数(1和自身) } // 遍历已找到的质数,更新倍数的信息 for (int j = 1; j <= cnt && i * pri[j] < N; j++) { vis[i * pri[j]] = pri[j]; // 标记非质数,记录最小质因子 d[i * pri[j]] = d[i] << 1; // 初始约数个数翻倍(假设互质) if (!(i % pri[j])) { // 若pri[j]是i的质因子 // 修正约数个数计算 d[i * pri[j]] -= d[i / pri[j]]; break; // 保证每个数只被最小质因子筛一次 } } } } // 主函数 signed main() { init(); // 预处理约数个数 int n = read(); // 读取查询次数 // 处理每个查询并输出结果 while (n--) printf("%d\n", solve()); return 0; }
- 1
信息
- ID
- 3164
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者