1030 完美数列 (25 分)
给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列。
现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。
输入格式:
输入第一行给出两个正整数 N 和 p,其中 N(≤105) 是输入的正整数的个数,p(≤109)是给定的参数。第二行给出 N 个正整数,每个数不超过 109。
输出格式:
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。
输入样例:
10 8
2 3 20 4 5 1 6 7 8 9
输出样例:
8
代码
//1.two pointers
#include <cstdio>
#include <algorithm>
using namespace std ;
int main() {
int n, p, A[100010] ;
scanf("%d %d", &n, &p) ;
for (int i=0; i<n; i++) {
scanf ("%d", &A[i]) ;
}
sort (A,A+n) ; //将数据按从小到大排序
int i=0, j=0, count=1 ; //将j右移找此时i对应的满足条件最大j
while (i<n && j<n) {
while (j<n && A[j]<=(long long)A[i]*p) {//相乘可能超出int范围,强制转换成长整型
count=max(count, j-i+1) ; //count:上一次的计数 j-i+1:当前计数
j++ ;
}
i++ ; //i右移
}
printf ("%d", count) ;
return 0 ;
}
//2.二分查找
#include <cstdio>
#include <algorithm>
using namespace std ;
int n, p, A[100010] ;
//在[i+1, n-1]内查找第一个大于x的数的位置
int binarysearch (int i, long long x) {
if (A[n-1]<=x) { //如果都不大于x,返回n
return n ;
}
int l=i+1, r=n-1, mid ; //在[i+1, n-1]内查找
while (l<r) {
mid=(l+r)/2 ;
if (A[mid]>x) {
r=mid ;
} else {
l=mid+1 ;
}
}
return l ; //返回该位置且此时l=r
}
int main() {
scanf("%d %d", &n, &p) ;
for (int i=0; i<n; i++) {
scanf ("%d", &A[i]) ;
}
sort (A,A+n) ; //按升序排序
int ans=1 ;
for (int i=0; i<n; i++) {
int j=binarysearch(i, (long long)A[i]*p) ;
ans=max(ans, j-i); //更新最大长度
}
printf ("%d", ans) ;
return 0 ;
}
//3.二分法可以直接使用upper_bound函数替代
//寻找第一个大于x的元素位置 upper_bound 函数
//寻找第一个大于等于x的元素位置 lower_bound 函数
//二分查找upper_bound函数
#include <cstdio>
#include <algorithm>
using namespace std ;
int main() {
int n, p, A[100010] ;
scanf ("%d %d", &n, &p) ;
for (int i=0; i<n; i++) {
scanf ("%d", &A[i]) ;
}
sort(A, A+n) ;
int ans=1 ;
for (int i=0; i<n; i++) {
int j=upper_bound(A+i+1, A+n, (long long)A[i]*p)-A ;
ans=max(ans, j-i) ;
}
printf ("%d", ans) ;
return 0 ;
}