应持续抓好二级网站的建设工作站长工具无忧
一、1.互质数的个数 - 蓝桥云课
算法代码(只能通过30%):
#include <bits/stdc++.h> // 包含所有标准库头文件,方便编程
using namespace std; // 使用标准命名空间,避免每次调用标准库函数时写 std::
typedef long long ll; // 定义 long long 类型的别名 ll,方便使用ll mod = 998244353; // 定义一个常量 mod,值为 998244353,用于模运算// 计算最大公约数(GCD)的函数
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a; // 递归实现欧几里得算法,b 为 0 时返回 a,否则递归计算 gcd(b, a % b)
}// 快速幂函数,计算 a 的 n 次方模 mod
ll fastPow(ll a, ll n) {ll ans = 1; // 初始化结果为 1a %= mod; // 对 a 取模,避免溢出while (n) { // 当 n 不为 0 时循环if (n & 1) { // 如果 n 的最低位是 1ans = (ans * a) % mod; // 将 a 乘到结果中,并对 mod 取模}a = (a * a) % mod; // 将 a 平方,并对 mod 取模n >>= 1; // 将 n 右移一位,相当于 n /= 2}return ans; // 返回最终结果
}int main() {ll a, b; // 定义两个长整型变量 a 和 bcin >> a >> b; // 从标准输入读取 a 和 b 的值ll mi = fastPow(a, b); // 计算 a 的 b 次方模 mod,结果存储在 mi 中ll ans = 0; // 初始化计数器 ans 为 0for (int i = 1; i < mi; i++) { // 遍历从 1 到 mi-1 的所有整数if (gcd(i, mi) == 1) { // 如果当前整数 i 与 mi 的最大公约数为 1(即互质)ans++; // 计数器 ans 加 1}}cout << ans; // 输出最终的计数结果return 0; // 程序正常结束
}
算法代码(通过100%):
// 本题主要考察欧拉函数和快速幂
// 欧拉函数 Euler(n): 表示不大于 n 且与 n 互质的正整数的个数,Euler(1) = 1
// 由唯一分解定理,n = p1^k1 * p2^k2 * ... * pn^km,pi 均为质数,ki 是其幂次
// 由此可推出欧拉函数的求法:Euler(n) = n / p1 * (p1 - 1) / p2 * (p2 - 1) / ... / pn * (pn - 1)
// 将欧拉函数的模板背下来即可
// 由欧拉函数的模板可知,若已知 Euler(a) = m,则 Euler(a^b) = m * (a^(b-1))
// 故先求 Euler(a),再用快速幂求 a^(b-1),二者相乘即为最终答案#include <bits/stdc++.h> // 包含所有标准库头文件,方便编程
using namespace std; // 使用标准命名空间,避免每次调用标准库函数时写 std::const int mod = 998244353; // 定义一个常量 mod,值为 998244353,用于模运算typedef unsigned long long ull; // 定义 unsigned long long 类型的别名 ull,方便使用// 快速幂算法,计算 base^power % mod
ull quick_power(ull base, ull power, ull mod) {ull res = 1; // 初始化结果为 1while (power) { // 当 power 不为 0 时循环if (power & 1) // 如果 power 的最低位是 1res = res * base % mod; // 将 base 乘到结果中,并对 mod 取模base = base * base % mod; // 将 base 平方,并对 mod 取模power = power >> 1; // 将 power 右移一位,相当于 power /= 2}return res % mod; // 返回最终结果
}// 求 n 的欧拉函数(固定模板)
ull Euler(ull n) {ull phi = n; // 初始化 phi 为 nfor (int i = 2; i * i <= n; i++) { // 枚举 n 的质因数if (n % i) continue; // 如果 i 不是 n 的因数,跳过while (n % i == 0) { // i 是质因数n = n / i; // n 不断除以 i 直至 i 不再是 n 的质因数}phi = phi / i * (i - 1); // 递推欧拉函数,Euler(n) = n / pi * (pi - 1)}// 最后可能还剩下一个大于 sqrt(n) 的质因数,如 12 = 2 * 2 * 3,最后将剩下 3,补充上if (n > 1) phi = phi / n * (n - 1);return phi; // 返回欧拉函数值
}// 由如上算法可知,n 的欧拉函数只与其质因数的组成有关,与每个质因数的个数无关
// 对于不同的数字,只要它们的质因数组成相同,计算过程中就会除以相同的 pi 乘以相同的 (pi - 1)
// 故若 m 和 n 的质因数组成相同,m 是 n 的 k 倍,则 Euler(m) 也是 Euler(n) 的 k 倍
// 而 a^b 是 a 的 a^(b-1) 倍,则由此推出 Euler(a^b) = Euler(a) * (a^(b-1)),此即为最终答案int main() {ull a, b; // 定义两个无符号长整型变量 a 和 bcin >> a >> b; // 从标准输入读取 a 和 b 的值ull Euler_a = Euler(a); // 计算 a 的欧拉函数值// 最终答案:Euler(a) * a^(b-1) % modull ans = Euler_a * quick_power(a, b - 1, mod) % mod;cout << ans << endl; // 输出最终答案return 0; // 程序正常结束
}
二、1.等差数列 - 蓝桥云课
算法代码:
#include <bits/stdc++.h> // 包含所有标准库头文件
using namespace std; // 使用标准命名空间int a[100000]; // 定义一个全局数组 a,用于存储输入的整数,最大容量为 100000int main() {int n; // 定义一个变量 n,用于存储输入的整数个数cin >> n; // 从标准输入读取整数个数 n// 循环读取 n 个整数并存储到数组 a 中for (int i = 0; i < n; i++) {cin >> a[i]; // 读取第 i 个整数并存储到数组 a 中}sort(a, a + n); // 对数组 a 中的元素进行升序排序int d = 0; // 定义一个变量 d,用于存储数组中相邻元素的差值的最大公约数(GCD)// 计算数组中相邻元素的差值的最大公约数for (int i = 1; i < n; i++) {d = __gcd(d, a[i] - a[i - 1]); // 更新 d 为当前 d 和相邻元素差值的 GCD}// 判断 d 是否为 0if (d == 0) {cout << n << endl; // 如果 d 为 0,说明所有元素相同,输出 n} else {// 如果 d 不为 0,计算等差数列的项数并输出printf("%d\n", (a[n - 1] - a[0]) / d + 1);}return 0; // 程序正常结束
}
主要思路:
三、1.核桃的数量 - 蓝桥云课
算法代码:
#include <bits/stdc++.h> // 包含所有标准库头文件
using namespace std; // 使用标准命名空间// 定义一个函数 lcm,用于计算两个数的最小公倍数
int lcm(int a, int b) {return a / __gcd(a, b) * b; // 使用公式 LCM(a, b) = (a * b) / GCD(a, b)
}int main() {int a, b, c; // 定义三个整数变量 a, b, ccin >> a >> b >> c; // 从标准输入读取三个整数 a, b, cint k = lcm(a, b); // 计算 a 和 b 的最小公倍数,并将结果存储在变量 k 中cout << lcm(k, c) << endl; // 计算 k 和 c 的最小公倍数,并输出结果return 0; // 程序正常结束
}
四、P1820 - [NewOJ Week 6] 最小公倍数 - New Online Judge
算法代码:
#include <bits/stdc++.h> // 包含所有标准库头文件
using namespace std; // 使用标准命名空间
typedef long long ll; // 定义 long long 类型为 ll,方便使用
const ll INF = 1e18; // 定义 INF 为 10^18,表示最大值
map<ll, pair<int, int>> ans; // 定义一个 map,存储 n 对应的区间 [L, R]// 预处理函数,计算所有可能的 n 对应的 [L, R]
void init() {// 遍历 L 从 1 到 2e6for (ll L = 1; L <= 2000000; L++) {ll n = L * (L + 1); // 计算 L 和 L+1 的乘积// 遍历 R 从 L+2 开始,逐步增加for (ll R = L + 2; ; R++) {ll g = __gcd(n, R); // 计算 n 和 R 的最大公约数// 检查是否溢出,如果溢出则跳出循环if (n / g > INF / R) break;n = n / g * R; // 更新 n 的值,防止溢出// 如果 n 还没有被存储过,则存入 map 中if (!ans.count(n)) {ans[n] = make_pair(L, R);}}}
}int main()
{init(); // 调用预处理函数int T; scanf("%d", &T); // 读取测试数据组数 Twhile (T--) {ll n; scanf("%lld", &n); // 读取每组测试数据的 n// 先判断区间长度为 2 的情况: [L, L+1]ll sqrt_n = sqrt(n + 0.5); // 计算 n 的平方根pair<int, int> res; // 定义结果变量 res// 检查是否存在区间 [sqrt_n, sqrt_n + 1] 满足条件if (sqrt_n * (sqrt_n + 1) == n) {res = make_pair(sqrt_n, sqrt_n + 1); // 如果满足条件,存储结果// 如果 map 中已经有更优的解,则更新 resif (ans.count(n))if(res.first > ans[n].first) res = ans[n];}else if (ans.count(n)) { // 如果 map 中有对应的解,则直接使用res = ans[n];} else { // 如果没有解,则输出 -1 并继续下一组测试puts("-1");continue;}printf("%d %d\n", res.first, res.second); // 输出结果}return 0;
}
代码思路
1. 预处理阶段
-
目标:预先计算所有可能的 n 值及其对应的区间 [L,R],并将结果存储在
map
中。 -
实现:
-
遍历 L 从 1 到 2×10^6。
-
对于每个 L,计算 L 和 L+1 的乘积 n。
-
遍历 R 从 L+2开始,逐步增加,计算区间 [L,R] 内所有整数的乘积 n。
-
使用最大公约数(
__gcd
)防止溢出,并更新 n 的值。 -
如果 n 没有被存储过,则将其存入
map
中。
-
2. 查询阶段
-
目标:对于每个输入的 n,找到对应的区间 [L,R] 或输出
-1
表示无解。 -
实现:
-
调用预处理函数
init()
,生成所有可能的 n 和 [L,R]的映射。 -
读取测试数据组数 T。
-
对于每组测试数据:
-
读取 n。
-
检查是否存在长度为 2 的区间 [L,L+1] 满足 L×(L+1)=n。
-
如果存在,则检查
map
中是否有更优的解(即 L 更小的解)。 -
如果
map
中有对应的解,则直接使用。 -
如果无解,则输出
-1
。 -
输出结果 [L,R]。
-
-
代码思路总结
-
预处理:
-
遍历 L 从 1 到 2×10^6。
-
对于每个 L,计算区间 [L,R] 的乘积 n,并存储到
map
中。 -
使用最大公约数防止溢出,确保计算正确。
-
-
查询:
-
对于每个输入的 n,先检查是否存在长度为 2 的区间 [L,L+1] 满足条件。
-
如果存在,则检查
map
中是否有更优的解。 -
如果
map
中有解,则直接使用;否则输出-1
。
-
-
输出:
-
输出每组测试数据的结果 [L,R] 或
-1
。
-
关键点
-
预处理优化:通过限制 L的范围(1 到 2×10^6),减少计算量。
-
防止溢出:使用最大公约数(
__gcd
)和先除后乘的方式,避免乘积溢出。 -
区间长度为 2 的特殊处理:单独检查 [L,L+1]的情况,减少计算复杂度。
-
结果存储:使用
map
存储 n 和 [L,R]的映射,方便快速查询。
代码结构
-
预处理函数
init()
:-
遍历 L 和 R,计算 n 并存储到
map
中。
-
-
主函数
main()
:-
调用
init()
进行预处理。 -
读取测试数据组数 T。
-
对于每组测试数据:
-
读取 n。
-
检查是否存在长度为 2 的区间 [L,L+1]。
-
检查
map
中是否有解。 -
输出结果。
-
-