来源: 第十届蓝桥杯省赛C++B组
算法标签: 数论最大公约数
题目描述
数学老师给小明出了一道等差数列求和的题目。
但是粗心的小明忘记了一部分的数列,只记得其中 N 个整数。
现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项?
输入格式
输入的第一行包含一个整数 N。
第二行包含 N 个整数 A1,A2,⋅⋅⋅,AN。(注意 A1∼AN 并不一定是按等差数
列中的顺序给出)
输出格式
输出一个整数表示答案。
数据范围
2≤N≤100000,
0≤Ai≤109
输入样例:
5
2 6 4 10 20
输出样例:
10
样例解释
包含 2、6、4、10、20 的最短的等差数列是 2、4、6、8、10、12、14、16、18、20。
思路
已知给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项
该数列为等差数列,求等差数列最短。
我们已知等差数列求N公式为(a(n)-a(0))/d+1
,即等差数列 队尾减队头的差 除以 公差 +1;
由此我们知道,本题根本不需要其余的队列数字,现在的问题转为,如何使得队伍从小到大排序
以及为(a(n)-a(0))/d+1
如何才能最短。
我们可以轻松的通过sort函数排序。
而使得 (a(n)-a(0))/d+1
最小则需要使得 公差最大。
由此,最后一步,我们只需要通过辗转相除法求得最大d,即可通过等差公式求得答案。
C++ 代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N];
int gcd(int a,int b)//辗转相除法 在两个数中求得最大公约数,当一方为0时,返回另一方。
{
return b?gcd(b,a%b):a;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
sort(a,a+n);//回复等差数列正常排序
int d=0;
for(int i=1;i<n;i++)d=gcd(d,a[i]-a[0]);//求得数列中的最大公约数,又因为辗转相除,所以gcd(a,b)中a,b任意一个为零时,可以返回另一个数,再和下一个数求最大公约数。
if(d)cout<<(a[n-1]-a[0])/d+1;//特判d为0!即有常数个,否则出现K/d时d==0逻辑错误Float Point Exception
else cout<<n;
return 0;
}