给定一个正整数数列,和正整数 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
思路:
记录下最大值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;
}