1. 程式人生 > >PAT乙級 1030 完美數列

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

在這裡插入圖片描述