【欢迎关注微信公众号:计算机黑科学大全,对话框回复:PAT乙级真题】获取全部真题详解及代码示例
个人博客地址:https://mzwang.top
完美数列
题目描述:
给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M ≤ mp,则称这个数列是完美数列。
现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。输入格式:
输入第一行给出两个正整数 N 和 p,其中 N(≤ 1 0 5 10^5 105)是输入的正整数的个数,p(≤ 1 0 9 10^9 109)是给定的参数。第二行给出 N 个正整数,每个数不超过 1 0 9 10^9 109。
输出格式:
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。
输入样例:
10 8 2 3 20 4 5 1 6 7 8 9
输出样例:
8
题目来源:PAT乙级1030
作者:CHEN, Yue
单位:浙江大学
方法一:递归方法,测试点4会超时
注意参数p和数组a[]要定义成long或long long型,否则会导致测试点5不通过,想一下为什么?输入后先对数组a[]进行升序排序,然后递归调用函数Max_Per_Array():
此法思路很简单,但是,运行效率不高,提交时测试点4会超时,因此有下面更高效的方法。
方法二:优化双层循环方法
先初始化完美数列最多元素个数,至少为1个;用双层循环,i从0开始依次递加作外层循环,a[i]为最小值,对于每一个i,j从i+max_coun开始,a[j]为最大值,判断是否满足完美数列的条件,若满足,则更新max_coun为当前完美数列的元素个数,即j-i+1,然后继续累加j继续判断直到跳出内层循环;若不满足,则直接跳出内存循环,因为若当前的j不满足,则后面的最大值更大,必不满足。
此法效率较高,不会出现超时。
小提示:请将以下代码保存为.cpp
格式(C++程序)左右滑动代码以查看完整代码
代码1
//递归方法,测试点4会超时
#include
#include
#define MAXN 100001
using namespace std;
int Max_Per_Array(long a[],int i,int j,long p);
int main()
{
int n;
long p;//定义为long型
scanf("%d%ld",&n,&p);
long a[MAXN];//定义为long型
for(int i = 0; i < n; i++){
scanf("%ld",&a[i]);
}
sort(a,a+n);//升序排序
int max_coun;
max_coun = Max_Per_Array(a,0,n-1,p);
printf("%d",max_coun);
return 0;
}
//返回数组a[]从第i到第j个位置能构成完美数列的最大元素个数
int Max_Per_Array(long a[],int i,int j,long p)
{
if(a[j] <= p * a[i]){//满足完美数列
return j-i+1;
}
else{//不满足完美数列
if(a[j - 1] > p * a[i]&&a[j] <= p * a[i + 1]){//最大值前移一位满足而最小值后移一位不满足
return Max_Per_Array(a,++i,j,p);//直接让最小值后移一位
}
else if(a[j - 1] <= p * a[i]&&a[j] > p * a[i + 1]){//最大值前移一位不满足而最小值后移一位满足
return Max_Per_Array(a,i,--j,p);//直接让最大值前移一位
}
else{//最大值前移一位或最小值后移一位都不满足则分别前移和后移
int ch_min,ch_max;
ch_min = Max_Per_Array(a,++i,j,p);
ch_max = Max_Per_Array(a,i,--j,p);
return ch_min > ch_max ? ch_min : ch_max;//返回最大元素个数
}
}
}
代码2
//优化双层循环方法,全部通过测试点
#include
#include
#define MAXN 100001
using namespace std;
int main()
{
int n;
long p;
scanf("%d%ld",&n,&p);
long a[MAXN];
for(int i = 0; i < n; i++){
scanf("%ld",&a[i]);
}
sort(a,a+n);//升序排序
int max_coun = 1;//完美数列最多元素个数,至少1个
for(int i = 0; i < n; i++){
for(int j = i + max_coun; j < n; j++){//最大值从最小值位置加上当前完美数列最多元素个数处开始即可
if(a[j] <= a[i] * p){//满足完美数列
max_coun = j - i + 1;//更新最多元素个数
}
else{//不满足直接跳出循环,j再往后,最大值会更大,更不会满足
break;
}
}
}
printf("%d",max_coun);
return 0;
}