原题干:
给定一个正整数数列,和正整数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
这道题给的数比较大,用int亲测不会通过,这里我使用的是long long。
先排序,在从前和从后分别遍历。如果全部遍历亲测会超时。
这里我们只遍历部分就可以。代码如下
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(){
int n;
long long p;
cin >> n >> p;
vector<long long int> a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
sort(a.begin(), a.end());
int result = 1;
for (int i = 0; i < n - 1; i++) {
for (int j = i + result; j < n; j++) {
if (a[j] > a[i] * p) break;
result = max(result, j - i + 1);
}
}
cout << result;
return 0;
}
另外一种办法是使用二分法,遍历排好序的数组,对于每一个值,使用二分找到小于等于它的上限(p倍)的位置,然后计算距离即可得到序列元素个数。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int main(){
size_t N, p, arr[maxn] = {0}, _max_len = 0;
cin >> N >> p;
for(size_t i = 0; i < N; i++) cin >> arr[i];
sort(arr, arr + N);
for(size_t i = 0; i < N; i++){
size_t high = arr[i] * p; //上限为最小值*p
size_t* _high = lower_bound(&arr[i], arr + N, high);
if(_high == arr + N) _high--; //如果没找到
if(*_high > high) _high--;
_max_len = max(_max_len, (size_t)(_high - &arr[i] + 1));
}
cout << _max_len << endl;
return 0;
}