Greatest Common Divisor(gcd性质)

题意

给定n个正整数ai,问它们至少同时加多少,可以使得它们的最大公约数大于1

若不存在,则输出1

数据范围

1T20
1n105
1ai109

思路

最大公约数性质

  • 更相减损术(引用李煜东《算法竞赛进阶指南》)

a,bN,ab,有gcd(a,b)=gcd(b,ab)=gcd(a,ab)

a,bN,有gcd(2a,2b)=2gcd(a,b)

证明:

根据最大公约数的定义,后者显然成立,我们主要证明前者。

对于a,b的任意公约数d,因为d|a,d|b,所以d|(ab)。因此d也是b,ab的公约数,反之也成立。故a,b的公约数集合与b,ab的公约数集合相同。于是,它们的最大公约数自然也相等。对于a,ab同理。

  • 推论
    a,b,cN,abc,有gcd(a,b,c)=gcd(a,ba,cb)

证明:

gcd(a,b,c)=gcd((a,b),(b,c))=gcd((a,ba),(b,cb))=gcd(a,ba,b,cb)

由于gcd(a,ba)=gcd(b,ba),则gcd(a,ba,b,cb)=gcd(a,ba,cb)=gcd(a,b,c)

本题做法

我们再回到本题中来,这道题的最终目标就是gcd(a1+k,a2a1,a3a2,,anan1)>1

我们可以将其拆成两部分,第一部分是a1+k,第二部分是a2a1,a3a2,,anan1

若后一部分的最大公约数是1,那么两部分的最大公约数就肯定是1,这种情况就是无解的。

若后一部分的最大公约数是x,x1,那么我们就考察x及其约数与第一部分的关系。我们不妨设x及其约数为q,我们需要找的是满足a1+k=sq,s>1的最小值。

a1=sqk可得,k=a1/qqa1

最后要注意的一点是所有数相同的情况,若所有数都是1,那么输出1;若都不是1,那么输出0

代码

#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;
}
posted @   pbc的成长之路  阅读(354)  评论(3编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· 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 让容器管理更轻松!
点击右上角即可分享
微信分享提示