牛客挑战赛47 A 一道GCD问题

牛客挑战赛47 A题


题目链接: https://ac.nowcoder.com/acm/contest/10743/A
来源:牛客网

题目描述

给定一个数组 a a a。现在让每个数都加上同一个非负整数 k k k,使得所有数的 g c d gcd gcd(最大公约数)尽可能大。

求这个 g c d gcd gcd最大值以及 k k k的值。如果有多个 k k k能得到这个最大的, g c d gcd gcd那么输出 k k k的最小值。

保证数组长度不小于2,且至少有两个不相同的数!

输入描述:

第一行一个正整数 ( 2 ≤ n ≤ 100000 ) (2≤n≤100000) (2n100000)
第二行个正整数 a i a_i ai ( 1 ≤ a i ≤ 1 0 9 ) (1≤a_i≤10^9) (1ai109)

输出描述:

一行两个数,分别代表最终 g c d gcd gcd的最大值、以及达到这个最大值的最小的 。

示例1

输入

2
1 3

输出

2 1

根据多维的更相减损术得 g c d ( x , y , z ) = g c d ( x , y − x , z − y ) gcd(x,y,z)=gcd(x,y−x,z−y) gcd(x,y,z)=gcd(x,yx,zy)
可得: g c d ( a 1 + k , a 2 + k , a 3 + k , . . . , a n + k ) = g c d ( a 1 + k , a 2 − a 1 , a 3 − a 2 , . . . ) gcd(a_1+k,a_2+k,a_3+k,...,a_n+k) = gcd(a_1+k,a_2-a_1,a_3-a_2,...) gcd(a1+k,a2+k,a3+k,...,an+k)=gcd(a1+k,a2a1,a3a2,...)

那么 根据后面n个数的 g c d gcd gcd来确定 a 1 + k a_1+k a1+k的值(使 a 1 + k a_1+k a1+k为的 g c d gcd gcd的倍数)

a 1 + k = n ∗ g c d a_1+k = n*gcd a1+k=ngcd n ∈ ( 1 , 2 , 3 , . . . ) n\in(1,2,3,...) n(1,2,3,...)


AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
long long a[N];
int main() {
	int n; 
	cin >> n;
	for (int i = 1; i <= n; i++) 
		cin >> a[i];
	sort(a + 1, a + n + 1);  //先排序
	long long gcd = 0;
	for (int i = 2; i <= n; i++) 
	{
		gcd = __gcd(gcd, a[i] - a[i - 1]);
	}
	cout<<gcd<<" ";
    //求k的最小值 最初是这么写的
	int k=0;
	while(1)
    {
        if((a[1]+k) % gcd == 0)  //如果a[1]+k为gcd的倍数 那么此时的k最小
        {
            cout<<k<<endl;
            break;
        }
    }
	
	return 0;
}

优化了一下求k的过程:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
long long a[N];
int main() {
	int n; 
	cin >> n;
	for (int i = 1; i <= n; i++) 
		cin >> a[i];
	sort(a + 1, a + n + 1);
	long long gcd = 0;
	for (int i = 2; i <= n; i++) 
	{
		gcd = __gcd(gcd, a[i] - a[i - 1]);
	}
	cout<<gcd<<" ";
    //优化代码
	int k=0;
	while((a[1]+k) % gcd) 
		k++;
	cout<<k<<endl;
	return 0;
}

参考大佬的代码:

求最小值k的方式真是妙啊~

如果 a [ 1 ] ≠ n × g c d a[1] ≠ n×gcd a[1]=n×gcd ( n ∈ ( 1 , 2 , 3... ) ) (n\in(1,2,3...)) (n(1,2,3...)) g c d − a [ 1 ] gcd-a[1]%gcd gcda[1]就是最小值k

如果 a [ 1 ] = g c d a[1] =gcd a[1]=gcd ( n ∈ ( 1 , 2 , 3... ) ) (n\in(1,2,3...)) (n(1,2,3...)) 那么 g c d − a [ 1 ] gcd-a[1]%gcd gcda[1] 还是 g c d gcd gcd ,需要再对 g c d gcd gcd取余

合成一个式子: ( g c d − a [ 1 ] % g c d ) % g c d (gcd - a[1] \% gcd) \% gcd (gcda[1]%gcd)%gcd

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
long long a[N];
int main() {
	int n; 
	cin >> n;
	for (int i = 1; i <= n; i++) 
		cin >> a[i];
	sort(a + 1, a + n + 1);
	long long gcd = 0;
	for (int i = 2; i <= n; i++) 
	{
		gcd = __gcd(gcd, a[i] - a[i - 1]);
	}
	cout << gcd << " " << (gcd - a[1] % gcd) % gcd << endl;
	return 0;
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值