资源限制
时间限制:1.0s 内存限制:256.0MB
思路简介
既然是求最短等差数列,显然一定是以最小的为数列首元素,最大的为末尾元素。先利用sort函数升序排列元素。然后采用暴力枚举公差的方法,(暂时不了解暴力枚举 算法的可以戳此链接,也可以看一下我之前的一些博客,包括典题和详解以及AC代码)
洛谷P1217 [USACO1.5]回文质数 Prime Palindromes 暴力枚举 C++_Prudento的博客-CSDN博客洛谷P1149 [NOIP2008 提高组] 火柴棒等式 暴力枚举 C++(打表)_Prudento的博客-CSDN博客_c++火柴棒完美立方 暴力枚举 C++_Prudento的博客-CSDN博客_c++ 暴力枚举生理周期 暴力枚举 C++_Prudento的博客-CSDN博客
称硬币 暴力枚举 C++_Prudento的博客-CSDN博客
洛谷P1618 三连击(升级版)C语言 暴力枚举 详解_Prudento的博客-CSDN博客_c语言暴力枚举
洛谷 P2089 烤鸡 C语言 (暴力枚举)_Prudento的博客-CSDN博客
前面说到要暴力枚举公差d,即 d从0枚举到最大值和最小值之差(其实没必要枚举这么多,只要枚举到一半就行,但是其实枚举到最大只差也不会TLE,所以避免一些特殊情况,那就干脆枚举的最大值设为此)。为什么最大值设成这个而不是其他?因为显然,当公差为最大值和最小值之差时,那么最小的元素和最大的元素应该是相邻的,那么此时只有n=2此公差才可能合法。n>2时此公差枚举到这显然肯定不合法了,更大的肯定更不合法。所以便确定的枚举变量d的范围。但是要注意,对于公差为0,即常数列可以O(n)的速度特判一下,如果是那么直接输出并结束程序。因为如果是常数列显然最短长度就是原数列的长度。那么下一步则确定如何对枚举变量进行操作,便是遍历每一位元素,只要(最大的元素-每一位元素)%d=0,说明此公差是合法的,每个数的间距都是公差的倍数。
确定公差合法后,那么项数便是(此处为升序排列)(最大值-最小值)/d+1
最后对每一次合法的公差取使得数列长度最短的即可。
Code
#include<bits/stdc++.h>
using namespace std;
int n,len=0x3f3f3f3f,i,d,tlen,flag,t;
int a[100010];
int now[100010];
inline int read() {//利用getchar比scanf快从而实现快读
char ch = getchar(); int x = 0;
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}return x;
}
int main(){
n = read();
for (i = 1; i <= n; i++)
now[i] = read();
sort(now + 1, now + 1 + n);
t = now[1];
for (i = 2; i <= n; i++) {
flag = t - now[i];
if (flag)break;//如果flag!=0,说明不可能是常数列
}//查看是否所有的数相同
if (!flag) {
printf("%d", n);
exit(0);
}//flag始终是0说明是常数列,直接输出最短长度便是现在的长度,并终止程序
//非常数列,枚举公差从1到最大的值和最小的值的差
for (d = 1; d <=now[n]-now[1]; d++) {//从1开始枚举公差
for (i=1; i <= n; i++)
if ((now[n]-now[i])%d)break;//如果两数之差取余公差不为0,那么此公差非法
if (i == n+1) {//说明此公差合法
tlen = (now[n] - now[1]) / d + 1;//项数
len = min(tlen, len);
}
}
printf("%d", len);
return 0;
}