https://ac.nowcoder.com/acm/contest/6112/C

description:

有个n个数 希望求一个x 使得每个数 +x 的gcd 值最大 ,求出gcd值 和 最小的x

solution:

gcd的性质: gcd(x,y) = gcd(x,y - x) 三个数也是一样
从这个式子可以看出所有数+x之后 他们之间的差值不变 并且 gcd的值也不会变
所以求出他们的差分数组 将差分数组gcd就是最大的gcd值
求的x 就是要在数组中一个最小的数 使得它变成gcd的倍数 对于每个数 如果本身就可以被整除 答案就是0
否则 分成负数和正数 两种情况 处理%gcd的值即可

code:

#include <bits/stdc++.h>

using namespace std;

#define LL long long

const int N = 1e6 + 50;

LL a[N];
vector <LL> v;

int main(){
    int n;scanf("%d",&n);

    for(int i = 1;i <= n;i ++){
        scanf("%lld",&a[i]);
    }

    sort(a + 1,a + 1 + n);

    for(int i = 2;i <= n;i ++){//求差分数组
        v.push_back(a[i] - a[i - 1]);
    }

    LL gcd = -1;
    for(int i = 0;i < v.size(); i ++){//求最终的gcd值 复杂度n + logai
        if(gcd == -1){
            gcd = v[i];
        }else{
            gcd = __gcd(gcd,v[i]);
        }
    }

    LL res = (LL)1e18;// 最大值
    for(int i = 1;i <= n;i ++){
        if(a[i] % gcd == 0){
            res = 0;
        }else{
            LL t;
            if(a[i] < 0){
                t = - (a[i] % gcd);
            }else{
                t = gcd - (a[i] % gcd);
            }
            res = min(res,t);
        }
    }

    printf("%lld %lld\n",gcd,res);

    return 0;
}