我们可以把该题分为两个模块:
- 如何通过给定的数组,算出得到最大公约数 g
- 如何根据 g 或者 直接 求出k
对于问题1,我们不难发现
当 g | (ai + k) 且 g | (aj + k) 时, g | (ai+k) - (aj+k) = g | (ai-aj)
前者为mg,后者为ng,最后两者相减为 (m-n)g,依旧可以被 g 整除
所以能得出重要性质:g 这个最大公约数,可以整除数组中任意两个数的差值
同时,当 g | (ai - a1) 且 g | (aj - a1) 时,同理能够得到 g | ai - a1 - aj + a1 = g | ai - aj
所以只要求出所有数和a1的差值的最大公约数,这个最大公约数就可以作为所有数对的差值的最大公约数
因此,只需要求出gcd((a1-a1),(a2-a1),(a3-a1),(a4-a1),……,(an-a1))即可
对于问题2,我们此时已经得到了 a1 + k = mg 中的 a1 与 g ,所以可以先去思考是否可以通过这个关系式得到 k
假设 a1 % g = r,那就有 mg + r = a1;又 g | a1 + k ,所以 g | mg + r + k
mg 肯定能够被 g 整除,所以我们现在只需要满足 r + k 可以被g整除即可,所以我们可以得到:
r + k = ng ( n = 1,2,3,……)
当 r = 0 时,a1 可以直接被 g 整除,此时 k = 0
当 r != 0 时,要求 k 最小,那么此时 n 取 1,所以 k = g - r
剩下的注意点:
- 求 gcd 时,我们要保证差值为正,这样用 gcd 函数才能求出正确的解;所以我们可以排序,让 a1 = 数组最小值
- gcd 用辗转相除法来求
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e6 + 10;
int a[N];
int gcd(int a,int b)
{
return b == 0 ? a : gcd(b,a%b);
}
signed main()
{
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1,less<int>());
int x = gcd(0,a[2]-a[1]);
for(int i=3;i<=n;i++)
x = gcd(x,a[i]-a[1]);
//x即为最大公约数
int r = a[1] % x;
if(!r) cout<<x<<" "<<0;
else cout<<x<<" "<<(x-r);
return 0;
}

京公网安备 11010502036488号