「作业」辗转相除法
A. 最大公约数和最小公倍数#
传送门:水滴
板子,虽然我已经能推出来了但还是要背一背(
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 5;
ll a, b;
inline int gcd (int x, int y) {
if(y == 0) return x;
else return gcd(y, x % y);
}
inline int lcm (int x, int y) {
return x * y / gcd(x, y);
}
int main(){
scanf("%lld%lld", &a, &b);
cout << gcd(a, b) << ' ' << lcm(a, b) << '\n';
return 0;
}
B.最大公约数和最小公倍数问题#
传送门:水滴
题目大意:给出正整数 x,y,找出 P,Q 使 x 为它们的最大公约数,y 是它们的最小公倍数,询问有几组满足条件的 P,Q。
首先要知道一个公式(与本题无关):x×y=gcd(x,y)×lcm(x,y)。
枚举 xy 的因数 1∼√xy,如果满足 gcd(i,xyi)=x,则增加答案。因为只枚举了乘积的一半,所以最终结果要乘 2。
当 x=y 时,会产生重复计算,所以要将 ans 减 1,
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 5;
inline int gcd (int x, int y) {
if (y == 0) return x;
else return gcd(y, x % y);
}
inline int lcm (int x, int y) {
return x * y / gcd(x, y);
}
int x, y;
int ans;
int main(){
scanf("%d%d", &x, &y);
for (int i = 1; i * i <= x * y; i++) {
if (x * y % i == 0 && gcd(i, x * y / i) == x)
ans ++;
}
ans *= 2;
if (x == y) ans --;
printf("%d", ans);
return 0;
}
C.Hankson 的趣味题#
传送门:水滴
题目大意:给你正整数 a0,a1,b0,b1,询问你有多少个 x 满足 gcd(x,a0)=a1,lcm(x,b0)=b1。
首先考虑暴力,发现数据 2×109,否掉。考虑优化,首先联想到质数只需要枚举一半的数,那么再一次循环中可以用性质来得出对应的大数(即用小因数除出来),然后判断即可。考虑进一步优化,发现 b1 模上当前循环的数为 0 时才会对答案有贡献,所以当 b1 为 0 时才进行判断会进一步优化时间。时间复杂度是 O(√n)。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 5;
inline ll gcd (ll x, ll y) {
if (y == 0) return x;
else return gcd(y, x % y);
}
inline ll lcm (ll x, ll y) {
return x * y / gcd(x, y);
}
int n;
ll a0, a1, b0, b1;
void solve() {
int ans = 0;
scanf("%lld%lld%lld%lld", &a0, &a1, &b0, &b1);
for (int i = 1; i * i <= b1; i++) {
if (b1 % i == 0) {
if (gcd(i, a0) == a1 && lcm(i, b0) == b1)
ans ++;
int x = b1 / i;
if (x != i && gcd(x, a0) == a1 && lcm(x, b0) == b1)
ans ++;
}
}
printf("%d\n", ans);
}
int main(){
scanf("%d", &n);
while (n--) solve();
return 0;
}
D. 最大公约数#
传送门:水滴
题目大意:给定 n 个正整数。每次可以进行一次操作:将相邻的两个数中的一个变成这两个数的最大公约数,询问你需要几次可以把这 n 个数都变为 1。
考虑暴力。首先推一遍样例,发现 1 是一个重要性质,可以去选择构造一个 1。当原数组中有 1 时,1 可以一个一个把周围的数变为 1。设 1 的数量是 cnt,则答案为 n−cnt。
考虑如果原数组中没有 1 的情况。设构造出一个 1 的次数是 sum,可以发现最后的答案就是 n+sum−1。
因为要找最小值,所以我们要找出最小的 sum,设它为 ans,答案就是 n+ans−1。考虑如何遍历。发现可以 O(n) 扫一遍数组寻找一个点,暴力看这个点能在多少步往后 gcd 出来一个 1,步数为 sum。初始化时把 ans 设为无穷大。循环时找到 1 就 ans 和 sum 取 min,最后就能找到 ans。
如果最后 ans 还是开始的无穷大,就说明没有解,输出 -1
。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 5;
inline int gcd (int x, int y) {
if(y == 0) return x;
else return gcd(y, x % y);
}
inline int lcm (int x, int y) {
return x * y / gcd(x, y);
}
int n;
int a[maxn];
int ans = INT_MAX;
int main(){
scanf("%d", &n);
int cnt = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i] == 1) cnt ++;
}
if (cnt) return printf("%d", n - cnt), 0;
for (int i = 1; i < n; i++) {
int x = a[i];
int sum = 0;
for (int j = i + 1; j <= n; j++) {
x = gcd(x, a[j]), sum++;
if (x == 1) {
ans = min(ans, sum);
break;
}
}
}
if (ans == INT_MAX) printf("-1\n");
else printf("%d", n + ans - 1);
return 0;
}
发现 TLE 了一个点,所以考虑用数据结构优化。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律