A1085 Perfect Sequence (25分)
题目描述
Given a sequence of positive integers and another positive integer p. The sequence is said to be a perfect sequence if M≤m×p where M and m are the maximum and minimum numbers in the sequence, respectively.
Now given a sequence and a parameter p, you are supposed to find from the sequence as many numbers as possible to form a perfect subsequence.
Input Specification:
Each input file contains one test case. For each case, the first line contains two positive integers N and p, where N (≤ 10 5 10^5 105) is the number of integers in the sequence, and p (≤ 1 0 9 10^9 109) is the parameter. In the second line there are N positive integers, each is no greater than 1 0 9 10^9 109.
Output Specification:
For each test case, print in one line the maximum number of integers that can be chosen to form a perfect subsequence.
Sample Input:
10 8
2 3 20 4 5 1 6 7 8 9
Sample Output:
8
题目大意
从N个正整数中选择若干个数,使得选出的这些数中的最大值不大于最小值的p倍。找出选出的数最多可能有多少个
思路
将给的数组按照递增排序,在这个递增的数列中确定一个最小值a[i],最大值a[j]使得a[j]≤a[i]*p成立,且j-i是所有满足条件的情况中的最大值。
(每找到一种满足条件的情况都要更新最大值)
注意点
- a[i]*p≤ 1 0 18 10^{18} 1018,所以这里需要注意数据类型设置为long long。(也可以一开始就将序列中的数直接定义为long long型)
- 单独判断当序列中的所有的数都不超过a[i]*p的情况
- 本题的数据用双重遍历是肯定会超时的
过程中犯的错误
- 刚开始头脑简单(
还心想着这不是贪心题嘛,这么简单)写代码的时候无形中将最小的数确定为排序后数组的a[0],求的是对于最小数是a[0]的情况下的结果
(意识到错误之后并没能立马反应过来用二分法写应该是怎么样的一个思路)
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#define Maxn 100001
using namespace std;
int a[Maxn];
int main(){
int N,p;
scanf("%d%d",&N,&p);
for(int i=0;i<N;i++)
scanf("%d",&a[i]);
sort(a,a+N);
int res=0;
for(int i=N-1;i>=0;i--){
if(a[i]*a[0]<=p){
res=i+1;
break;
}
}
printf("%d\n",res);
return 0;
}
最终正确代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#define Maxn 100001
using namespace std;
int n,p,a[Maxn];
//在[i+1,n-1]范围内查找第一个大于x的数字的位置(所以最终的长度是函数返回值-i)
int binaryfind(int i,long long x){
int left=i+1,right=n-1,mid;
if(a[n-1]<=x)
return n;
else{
while(left<right){
mid=(left+right)/2;
if(a[mid]<=x){
left=mid+1;
}else{
right=mid;
}
}
}
return left;//while结束时left=right,因此返回left或者right都是可以的
}
int main(){
scanf("%d%d",&n,&p);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int res=1;
for(int i=0;i<n;i++){
int temp=binaryfind(i,(long long) a[i]*p);
res=max(res,temp-i);//更新最大的长度
}
printf("%d\n",res);
return 0;
}
算法笔记里的另一个写法
书上将二分查找直接用upper_bound函数进行代替,使得代码简介很多。