1. 程式人生 > >hdoj-1280-前m大的數【計數排序】

hdoj-1280-前m大的數【計數排序】

前m大的數

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 13743 Accepted Submission(s): 4683


Problem Description 還記得Gardon給小希佈置的那個作業麼?(上次比賽的1005)其實小希已經找回了原來的那張數表,現在她想確認一下她的答案是否正確,但是整個的答案是很龐大的表,小希只想讓你把答案中最大的M個數告訴她就可以了。
給定一個包含N(N<=3000)個正整數的序列,每個數不超過5000,對它們兩兩相加得到的N*(N-1)/2個和,求出其中前M大的數(M<=1000)並按從大到小的順序排列。
Input 輸入可能包含多組資料,其中每組資料包括兩行:
第一行兩個數N和M,
第二行N個數,表示該序列。


Output 對於輸入的每組資料,輸出M個數,表示結果。輸出應當按照從大到小的順序排列。
Sample Input 4 4 1 2 3 4 4 5 5 3 6 4
Sample Output 7 6 5 5 11 10 9 9 8
Author Gardon
Source
Recommend lcy | We have carefully selected several similar problems for you:
1029
1264 1800 2522 2600 此題第一感覺就是把兩兩相加的結果都儲存到一個數組中,然後排序即可了,可是仔細一看,陣列的大小要開到: N*(N-)/2 ,N為3000,那麼也就是說陣列要開到:4500000;肯定會超記憶體的吧,再加上要排序,時間和空間的耗費都挺大; 不過注意到題中說:每個數不超過5000,那麼任意兩個數的和都不會超過10000;所以這些和中一定存在重複的,這樣就可以把和作為新陣列的下標,陣列內容存的是重複和的個數,這樣的話在查詢 前m大時,也不需要進行排序了,直接在新陣列中從 下表為 10000開始往前查詢即可了,因為不是基於比較的基礎查詢的,時間大大節約,時間複雜度約為:O(n),而空間也有很大的優化
#include<stdio.h> 
#include<string.h> 
int a[3000],c[10000+1];
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		memset(c,0,sizeof(c));
		int i,j;
		for(i=0;i<n;++i){
			scanf("%d",&a[i]);
		}
		for(i=0;i<n;++i){
			for(j=i+1;j<n;++j){
				c[a[i]+a[j]]++;
			}
		}
		for(i=10000;m>0;){
			if(c[i]&&m>1){
				printf("%d ",i);
				m--;
				c[i]--;
			}
			else if(c[i]&&m==1){
					printf("%d\n",i);
					m--;
					c[i]--;
			}
			else i--;
		}
	}
	return 0;
}