1085 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 (≤105) is the number of integers in the sequence, and p (≤109) is the parameter. In the second line there are N positive integers, each is no greater than 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

还熟悉二分的写法就很简单,不要怕,暴力基础上做一点优化即可。  若记得api  upper_bound就更简单了

手写:

#include<bits/stdc++.h>
using namespace std;
long long N,p,a[100010];

//返回数组a中第一个大于x的元素的下标
int Upper_bound(int i,long long x){
if(a[N-1]<=x) return N;//都小于 返回最大下标+1 含义是x应该插入的位置
int left=i+1,right=N-1;//p至少为1 也即a[i]<=x=a[i]*p恒成立 所以从i+1开始算起
while(left<right){
int mid=(left+right)/2;
if(a[mid]>x){
right=mid;
}else{//a[mid]<=x
left=mid+1;//一点都不要多余 小于等于x时才+1 一步一步尝试,最终定是第一个大于x的位置
}
}
return left;
}

int main(){
//freopen("in.txt","r",stdin);
cin>>N>>p;
for(int i=0;i<N;i++) cin>>a[i];
sort(a,a+N);
int ans=0;
for(int i=0;i<N;i++){
int j=Upper_bound(i,a[i]*p);
ans=max(ans,j-i);
}
cout<<ans;
return 0;
}

 

API:

#include<bits/stdc++.h>
using namespace std;
long long N,p,a[100010];
int main(){
//freopen("in.txt","r",stdin);
cin>>N>>p;
for(int i=0;i<N;i++) cin>>a[i];
sort(a,a+N);
int ans=0;
for(int i=0;i<N;i++){
int j=upper_bound(a+i,a+N,a[i]*p)-a;//-a才是下标 a+i+1开始最好
ans=max(ans,j-i);
}
cout<<ans;
return 0;
}

思路没错,分析得也对,a[i]*p->a[j] a[j]是第一个大于p*a[i]的数(中间都小于等于)   j-i就是答案 
直接二重循环肯定超时,10^5*10^5
二分的话可以  n*logn=5*10^5 不会超时
二分其实也很简单,每次寻找a[j]的代码换用二分法查找即可

记住upper_bound(a,a+n,val)    a[0~n-1]范围内(其实是[a,a+n)) 第一个大于val的位置指针   返回值-a就是下标

lower_bound(a,a+n,val)  同上,不过找的是第一个大于等于val的位置,返回值后面可能有等于val的,但没有大于val的 
  

 

two pointer做法 也很妙,每次保证i,j的距离最大  j能加就j++。i不到万不得已不i++    时间复杂度O(N)更短

#include<bits/stdc++.h>
using namespace std;

long long N,p,a[100010];

int main(){
// freopen("in.txt","r",stdin);
cin>>N>>p;
for(int i=0;i<N;i++) scanf("%d",&a[i]);
sort(a,a+N);
int i=0,j=0,count=0;
while(i<N&&j<N){//O(N)
if(a[j]<=a[i]*p){
count=max(count,j-i+1);
j++;//j疯狂加 最终j先到N 结束
}else{
i++;//i不到万不得已不加
}
}
cout<<count;
return 0;
}