PAT乙级 1030 完美数列

给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列。现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。

输入格式:

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

输出格式:

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

输入样例:

10 8
2 3 20 4 5 1 6 7 8 9

输出样例:

8

思路:

记录下最大值Max,从数组第一个开始,把每一个值都当做最小值m,看是否满足Max≤mp,满足则计数加一。

代码:

#include<stdio.h>
int main(){
	long Max=0;
	int N;
	long series[100000],p;
	scanf("%d %ld",&N,&p);
	int cnt=N;
	for(int i=0;i<N;++i){
		scanf("%ld",&series[i]);
		if(Max<series[i]) Max=series[i];
	}
	for(int i=0;i<N;++i){
		if(Max>series[i]*p) --cnt;
	}
	printf("%d",cnt);
	return 0;
}

在这里插入图片描述

遗留问题:

测试点4为什么无法通过呢?

第一次修改:

测试点四的错误大概是因为忽略了这样一个问题:包含最大数的完美数列的正整数个数可能没有以次大数为最大数的完美数列的正整数个数多。于是重新做了一次,这次先使用选择排序对数列进行了降序排序,然后检测每一个完美数列包含的正整数的个数,并取个数最多的那一个。

代码:

#include<stdio.h>
int main(){
	int N,sign=1,cnt;
	long series[100000],p;
	scanf("%d %ld",&N,&p);
	for(int i=0;i<N;++i){
		scanf("%ld",&series[i]);
	}
	for(int i=0;i<N-1;++i){
		int max=i;
		for(int j=i+1;j<N;++j){
			if(series[max]<series[j]){
				max=j;
			}
		}
		long temp=series[i];
		series[i]=series[max];
		series[max]=temp;
	}
	for(int i=0;i<N;++i){
		int k=0;
		for(int j=i;j<N;++j){
			if(series[i]<=series[j]*p){
				++k;
			}
			else{
				break;
			}
		}
		if(sign==1){
			cnt=k;
			sign=0;
		}
		else{
			if(cnt<k){
				cnt=k;
			} 
		}
	}
	printf("%d",cnt);
	return 0;
}

在这里插入图片描述

遗留问题:

测试点4运行超时。

第二次修改:

运行超时是因为选择排序的时间复杂度为O(n2),改用快速排序,其时间复杂度为O(N*logN)。
这里是大神对快速排序的讲解:https://blog.csdn.net/MoreWindows/article/details/6684558

代码:

#include<stdio.h>
void quick_sort(long s[], int l, int r)
{
    if(l<r){  
    	long temp=s[l];//将中间的这个数和第一个数交换
    	s[l]=s[(l+r)/2];
    	s[(l+r)/2]=temp;
    	int i=l,j=r,x=s[l]
        while(i<j){
            while(i<j&&s[j]<x) // 从右向左找第一个小于x的数
				j--;  
            if(i<j) 
				s[i++]=s[j];
            while(i<j&&s[i]>=x) // 从左向右找第一个大于等于x的数
				i++;  
            if(i<j) 
				s[j--]=s[i];
        }
        s[i]=x;
        quick_sort(s,l,i-1); // 递归调用 
        quick_sort(s,i+1,r);
    }
}
int main(){
	int N,sign=1,cnt;
	long series[100000],p;
	scanf("%d %ld",&N,&p);
	for(int i=0;i<N;++i){
		scanf("%ld",&series[i]);
	}
	quick_sort(series,0,N-1);
	for(int i=0;i<N;++i){
		int k=0;
		for(int j=i;j<N;++j){
			if(series[i]<=series[j]*p){
				++k;
			}
			else{
				break;
			}
		}
		if(sign==1){
			cnt=k;
			sign=0;
		}
		else{
			if(cnt<k){
				cnt=k;
			} 
		}
	}
	printf("%d",cnt);
	return 0;
}

在这里插入图片描述

遗留问题:

测试点4依然超时。

第三次修改:

这次参考网友的代码,改进了统计完美数列包含正整数的个数的方法,每次开始查找的范围随着cnt(完美数列元素个数)的值增大不断缩减。

代码:

#include<stdio.h>
void quick_sort(long s[],int l,int r)
{
    if(l<r){  
    	long temp=s[l];//将中间的这个数和第一个数交换
    	s[l]=s[(l+r)/2];
    	s[(l+r)/2]=temp;
    	int i=l,j=r,x=s[l];
        while(i<j){
            while(i<j&&s[j]>=x) // 从右向左找第一个小于x的数
				j--;  
            if(i<j) 
				s[i++]=s[j];
            while(i<j&&s[i]<x) // 从左向右找第一个大于等于x的数
				i++;  
            if(i<j) 
				s[j--]=s[i];
        }
        s[i]=x;
        quick_sort(s,l,i-1); // 递归调用 
        quick_sort(s,i+1,r);
    }
}
int main(){
	int N,cnt=1;
	long series[100000],p;
	scanf("%d %ld",&N,&p);
	for(int i=0;i<N;++i){
		scanf("%ld",&series[i]);
	}
	quick_sort(series,0,N-1);
	for(int i=0;i<N;++i){
		for(int j=i+cnt;j<N;++j){
			if(series[i]*p>=series[j]) ++cnt;
			else break;
		} 
	}
	printf("%d",cnt);
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值