题目内容:
给定一个正整数数列,和正整数 p ,设这个数列中的最大值是
M ,最小值是 m ,如果M≤m∗p ,则称这个数列是完美数列。现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。
输入格式:
输入第一行给出两个正整数
N 和 p ,其中N(≤105) 是输入的正整数的个数, p(≤109) 是给定的参数。第二行给出 N 个正整数,每个数不超过109 。输出格式:
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。
输入样例:
10 8 2 3 20 4 5 1 6 7 8 9
输出样例:
8
思路分析:
本题思路是从双层for循环,逐个组合验证的方法优化得来的。
- 对于任何两个满足
M≤m∗p
关系的数
M
和
m 对应的最长序列就是所有在 M 和m 之间的所有数。所以我先排序,后分析长度。 - 对于已知符合要求的最长序列,其长度为 count 。那么下面需要验证的就是所有长度大于 count 的序列。
验证时外层循环控制变量为 i,标记被验证序列的开始位置。内层循环的控制变量为 j 标记被验证序列的结束位置。变量 count 记录已知最长的完美数列长度。所以对于每一个 i,j 从 i+count 开始验证。i 在距离输入数据的最后元素距离为 count 时停止验证,因为 i 继续增大,得出的完美数列长度已经不可能超过已知,没有验证的必要。
代码:
#include <stdio.h>
#include <stdlib.h>
int comp(const void *a, const void *b)
{
return *(int*)a-*(int*)b;
}
int main()
{
int n = 0, p = 0, count = 0, temp = 0;
scanf("%d%d", &n, &p);
int ary[n];
for (int i = 0; i < n; i++)
scanf("%d", ary+i);
qsort(ary, n, sizeof(int), comp);
for (int i = 0; count != n && i < n - count; i++) { // 已知完美数列长度达到最大可能时,退出全部循环
for (int j = i + count; j < n; j++) { // 待验证数列结尾部分从i+count开始
if (j == n-1 || ary[j+1] > (long long)ary[i] * p) {
if (ary[j] <= (long long)ary[i] * p) {
// 当此时的ij组合满足完美数列,但下个j,不满足完美数列要求,此时的ij对为对于当前i的最大可能完美数列
temp = j - i + 1; // 计算当前数列长度
count = (temp > count) ? temp : count; // 跟已知的对比,取更大的一个
}
break;
}
}
}
printf("%d", count);
return 0;
}