Greatest Common Divisor(gcd性质)
题意
给定个正整数,问它们至少同时加多少,可以使得它们的最大公约数大于。
若不存在,则输出
数据范围
思路
最大公约数性质
- 更相减损术(引用李煜东《算法竞赛进阶指南》)
,有
,有
证明:
根据最大公约数的定义,后者显然成立,我们主要证明前者。
对于的任意公约数,因为,所以。因此也是的公约数,反之也成立。故的公约数集合与的公约数集合相同。于是,它们的最大公约数自然也相等。对于同理。
- 推论
,有
证明:
由于,则。
本题做法
我们再回到本题中来,这道题的最终目标就是
我们可以将其拆成两部分,第一部分是,第二部分是
若后一部分的最大公约数是,那么两部分的最大公约数就肯定是,这种情况就是无解的。
若后一部分的最大公约数是,那么我们就考察及其约数与第一部分的关系。我们不妨设及其约数为,我们需要找的是满足的最小值。
由可得,
最后要注意的一点是所有数相同的情况,若所有数都是,那么输出;若都不是,那么输出
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 100010;
int n;
ll a[N];
ll gcd(ll a, ll b)
{
return b ? gcd(b, a % b) : a;
}
int main()
{
int T;
scanf("%d", &T);
for(int cas = 1; cas <= T; cas ++) {
scanf("%d", &n);
ll sum = 0;
for(int i = 1; i <= n; i ++) {
scanf("%lld", &a[i]);
sum += a[i];
}
if(sum == n) {
printf("Case %d: 1\n", cas);
continue;
}
ll tmp = a[1];
for(int i = 2; i <= n; i ++) tmp = gcd(tmp, a[i]);
if(tmp > 1) {
printf("Case %d: 0\n", cas);
continue;
}
sort(a + 1, a + n + 1);
tmp = a[2] - a[1];
for(int i = 2; i < n; i ++) tmp = gcd(tmp, a[i + 1] - a[i]);
if(tmp == 1) {
printf("Case %d: -1\n", cas);
continue;
}
ll ans = ((a[1] - 1) / tmp + 1) * tmp - a[1];
for(ll i = 2; i <= tmp / i; i ++) {
if(tmp % i) continue;
ll k = tmp / i;
ans = min(ans, ((a[1] - 1) / i + 1) * i - a[1]);
ans = min(ans, ((a[1] - 1) / k + 1) * k - a[1]);
}
printf("Case %d: %d\n", cas, ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!