版权声明:关中大侠Lv轻侯 https://blog.csdn.net/weixin_44312186/article/details/88568417
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、首先要知道一个结论:能使选出的数的个数最大的方案,一定是在该递增序列中连续选择若干个数的方案(在此不作证明)
2、问题转化为:在一个递增数列中,确定一个左端点num[ i ],一个右端点num[ j ]使得num[ j ]<=num[ i ]*p成立并且j-i最大。
代码一(二分法):
//#include<bits/stdc++.h>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define maxnum 100001
using namespace std;
int N,M,p,m,num[maxnum];//定义变量
int ans=1;//最定义大个数
int binarysearch(int x,long long y)
{
if(num[N-1]<=y) return N;//若所有数都不大于y则返回N
int l=x+1,r=N-1,mid;
while(l<r)
{
mid=(l+r)/2;
if(num[mid]>y)
{
r=mid;
}
else
{
l=mid+1;
}
}
return l;//当while结束时l==r,故返回l或者r都可以
}
int main()
{
scanf("%d%d",&N,&p);
for(int i=0; i<N; i++)
{
scanf("%d",&num[i]);
}
sort(num,num+N);
for(int i=0; i<N; i++)
{
int j=binarysearch(i,(long long)p*num[i]);
ans=max(ans,j-i);//更新最大个数 (j-i 表示j和i之间的距离)
}
printf("%d\n",ans);
return 0;
}
代码二(使用upper_bound函数):
ps:upper_bound(int A[ ],int left,int right,int x)函数是求序列中第一个大于x的元素的位置
//#include<bits/stdc++.h>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define maxnum 100001
using namespace std;
int N,M,p,m,num[maxnum];//定义变量
int ans=1;//最定义大个数
int main()
{
scanf("%d%d",&N,&p);
for(int i=0; i<N; i++)
{
scanf("%d",&num[i]);
}
sort(num,num+N);
for(int i=0; i<N; i++)
{
int j=upper_bound(num+i+1,num+N,(long long)p*num[i])-num;//在num[i+1]到num[n-1]之间找出第一个大于 p*num[i]的元素位置
ans=max(ans,j-i);//更新最大个数 (j-i 表示j和i之间的距离)
}
printf("%d\n",ans);
return 0;
}
代码三(two pointers) :
ps:two pointers精髓:j永远增加的直到j==N(当i增加为下一个值时,j不是归零之后再增加,而是从刚才i未增加之前的j值继续增加)
//#include<bits/stdc++.h>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define maxnum 100001
using namespace std;
int N,M,p,m,num[maxnum];//定义变量
int ans=1;//最定义大个数
int main()
{
scanf("%d%d",&N,&p);
for(int k=0; k<N; k++)
{
scanf("%d",&num[k]);
}
sort(num,num+N);
int j=0;
for(int i=0;i<N;i++){
while (j<N&&num[j]<=(long long)num[i]*p)
{
ans=max(ans,j-i+1);
j++;//j永远增加的直到j==N(当i增加为下一个值时,j不是归零之后再增加,而是从刚才i未增加之前的j值继续增加)(two pointers的精髓)
}
}
printf("%d\n",ans);
return 0;
}