给定一个正整数数列,和正整数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
算法:
- 算法开始。
- 读入N和p。
- 读入所有数字,存于a[N],排序。
- i=0,max=0。
- 如果a[i]*p>a[N-1],则跳到
- 用二分法找出大于a[i]*p的最小数字的下表j。
- 如果j-i小于max而且如果p等于1或者j-i不等于1,max等于j-i。
- 回到第五步。
- 如果n-i小于max而且如果p等于1或者n-i不等于1,max等于n-i。
- 输出max。
- 算法结束。
#include<stdio.h>
#include<stdlib.h>
int cmp(const void* v1, const void* v2);
int find_min_larger(int* array, int i, int p, int n);
int main(void) {
int n, p;
int i, j;
int* array;
int max = 0;
double num;
scanf_s("%d %d", &n, &p);
array = (int*)calloc(n, sizeof(int));
for (i = 0; i < n; i++) {
scanf_s("%d", array + i);
}
qsort(array, n, sizeof(int), cmp);
num = (double)(array[0]) * (double)p;
for (i = 0; (num = (double)(array[i]) * (double)p) < array[n - 1]; i++) {
j = find_min_larger(array, i, p, n);
if ((j - i > max)&&(j - i != 1 || p == 1)) {
max = j - i;
}
}
if ((n - i > max) && ((n - i != 1)||p==1)) {
max = n - i;
}
printf("%d", max);
return 0;
}
int cmp(const void* v1, const void* v2) {
if (*((int*)v1) > *((int*)v2)) {
return 1;
}
else if(*((int*)v1)==*((int*)v2)){
return 0;
}
else {
return -1;
}
}
int find_min_larger(int* array, int i, int p, int n) {
int start = i + 1, end = n - 1, middle;
double num = p*array[i];
while (start < end) {
if (num < array[start]) {
return start;
}
else if (num >= array[end]) {
return end + 1;
}
else{
middle = (start + end) / 2;
if (array[middle] > num) {
end = middle - 1;
}
else {
start = middle + 1;
}
}
}
if (num < array[start]) {
return start;
}
else {
return start + 1;
}
}
上段代码对二分查找法的使用不是特别漂亮,现在修改如下。
#include<stdio.h>
#include<stdlib.h>
int cmp(const void* v1, const void* v2);
int find_min_larger(int* array, int i, int p, int n);
int main(void) {
int n, p;
int i, j;
int* array;
int max = 0;
double num;
scanf("%d %d", &n, &p);
array = (int*)calloc(n, sizeof(int));
for (i = 0; i < n; i++) {
scanf("%d", array + i);
}
qsort(array, n, sizeof(int), cmp);
num = (double)(array[0]) * (double)p;
for (i = 0; (num = (double)(array[i]) * (double)p) < array[n - 1]; i++) {
j = find_min_larger(array, i, p, n);
if ((j - i > max)&&(j - i != 1 || p == 1)) {
max = j - i;
}
}
if ((n - i > max) && ((n - i != 1) || p == 1)) {
max = n - i;
}
printf("%d", max);
return 0;
}
int cmp(const void* v1, const void* v2) {
return *((int*)v1) - *((int*)v2);
}
int find_min_larger(int* array, int i, int p, int n) {
int start = i + 1, end = n - 1, middle;
double num = p * array[i];
while (start < end) {
middle = (start + end) / 2;
if (num < array[middle]) {
end = middle;
}
else{
start = middle + 1;
}
}
return start;
}