题目描述
数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一 部分的数列,只记得其中 N 个整数。现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项?
输入描述
第一行输入一个整数n
第二行输入等差数量a0,a1,a2,···,a(n-1){需要注意等差数列不一定是按大小排列}
输出描述
输出一个整数。
示例
输入
5
2 6 4 10 20
输出
10
样例说明: 包含 2、6、4、10、20 的最短的等差数列是 2、4、6、8、10、12、14、16、 18、20。
解题思路
先将题目给出的等差数列排序,公差mid一定会小于等于相邻两项之和,对每相邻两项相减,求出最小的差值,设为mid,此时假设公差为mid。
1.对每相邻两项求差再对mid取余数,如果余数都为零那么mid就是最大的公差
2.如果不是公差不是mid,对mid自减,然后重复1过程,即可求出最大公差mid
3.因为sort排序为由小到大排序,所以不用考虑公差为负数的情况
最后,公差越大,项数越小,故(a(n-1)-a(0))/mid+1就是最小项。
因为等差数列的性质,它每相邻两项差恒为mid,那么它间隔m项的差为m*mid,即:对间隔m项的两项求差,差再对mid取余数,余数为0,所以本题可以使用取余的方法判断等差数列公差。
代码
#include<iostream>
#include<algorithm>
using namespace std;
//等差数列缺少项求等差数列最少多少项
int panduan(long* a, int n,int j)
{//判断j是否是公差
int i,m=1;
for (i = 0; i < n - 2; i++)
{
if ((a[i + 1] - a[i]) % j)
m = 0;//if函数里的表达式即为余数
}
return m;//m为1,j为公差,m为0,j不为公差
}
int main()
{
int n, mid = 100000, sum,i;
scanf("%d", &n);
long a[10000];
for (i = 0; i < n; i++)
{
cin >> a[i];
}
sort(a, a + n);//对等差数列排序
for (i = 0; i < n-2; i++)
{
if (a[i + 1] - a[i] < mid)
mid = a[i + 1] - a[i];
}
if (mid == 0)
sum = n;
for ( mid; mid!=0 ;mid--)
{
if (panduan(a, n, mid))
{
sum = (a[n - 1] - a[0]) / mid + 1;
break;
}
}
cout<< "最少项数为" << sum << endl;
cout<< "最大公差为" << mid << endl;
return 0;
}
结果
1、公差为0(通过差直接得出公差)
10
1 1 1 1 1 1 1 1 1 1
最少项数为10
最大公差为0
2、公差为1(通过差直接得出公差)
10
-2 6 0 -1 3 1 5 4 2 7
最少项数为10
最大公差为1
3、不能通过差直接得出公差
10
3 12 30 36 45 54 63 72 81 90
最少项数为30
最大公差为3
上述最小相邻差为36-30=6,与公差3不同。
5
1 6 9 16 21
最少项数为21
最大公差为1
与上一个相似。