题目描述
你N个正整数a[1]…a[N],在最初的时候,你选择一个正整数X,然后以后每一步,你可以使一个数a[i] 变成 a[i] + X,或者 a[i] - X,聪明的你,一定会知道怎么选择这个X,使得最后所有的数都变成相等,而且使用的变化步数最少。
输入
多组测试数据。对于每组数据,一个N(2 <= N <= 1000),接下来一行有N个数a[1]…a[N] (1 <= a[i] <= 10^6)。
保证这N个数不全相等。
输出
每组数据单独一行,你找出的正整数X,以及最少步数,两个数用一个空格隔开.
样例输入
3
1 2 3
4
3 5 7 11
样例输出
1 2
2 5
来源
BoilTask
#include<iostream>
#include<queue>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<stdio.h>
#define LL long long
using namespace std;
const int MAXN = 1e3+10;
const int MAXM = 1e6+100;
const int inf = 0x3f3f3f3f;
/*------------------------------*/
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int arr[MAXN];
int brr[MAXM];
int main(){
int n,m;
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++)
scanf("%d",&arr[i]);
// 这里找到的是任意两个之间的差值的 gcd。 (1)
int val=abs(arr[1]-arr[2]);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++){
val=gcd(val,abs(arr[i]-arr[j]));
}
sort(arr+1,arr+1+n);
/* (2) 别人的题解 。
sort(arr+1,arr+n+1);
for(int i=2;i<=n;i++)
brr[i-1]=arr[i]-arr[i-1];
int val=brr[1];
for(int i=2;i<=n-1;i++)
val=gcd(val,brr[i]);
*/
if(n&1) {
int k=(n+1)/2;
int cnt=0;
for(int i=1;i<=n;i++){
cnt+=abs(arr[i]-arr[k])/val;
}
printf("%d %d\n",val,cnt);
}
else {
int k=n/2;
int cnt=0;
for(int i=1;i<=n;i++){
cnt+=abs(arr[i]-arr[k])/val;
}
int l=0;k++;
for(int i=1;i<=n;i++){
l+=abs(arr[i]-arr[k])/val;
}
printf("%d %d\n",val,min(l,cnt));
}
}
return 0;
}
看了上部分的 (1)和(2),我就是无法理解别人的解,为什么只要求排序后的n-1个差值的gcd就可以满足题意,想了半天才想到。
假如一个排序好的 三个数 A B C 【由小到大】
x=gcd(B-A , C-B) y =gcd(B-A , C-B , C-A );
实际意义就是 x*n=B-A ,x*m=C-B . 如果这样的话, 那么x*(n+m) =C-A … 所以得证 x==y 。所以排好序,找n-1个差值的gcd就足够了。