1030 完美数列 (25 分)

版权声明:关中大侠Lv轻侯 https://blog.csdn.net/weixin_44312186/article/details/88568417

1030 完美数列 (25 分)

给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列。

现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。

输入格式:

输入第一行给出两个正整数 N 和 p,其中 N(≤10​5​​)是输入的正整数的个数,p(≤10​9​​)是给定的参数。第二行给出 N 个正整数,每个数不超过 10​9​​。

输出格式:

在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。

输入样例:

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;
}

猜你喜欢

转载自blog.csdn.net/weixin_44312186/article/details/88568417