題目描述
有N個人要參加國際象棋比賽,該比賽要進行K場對弈。每個人最多參加兩場對弈,最少參加零場對弈。每個人都有一個與其他人不相同的等級(用一個正整數來表示)。
在對弈中,等級高的人必須用黑色的棋子,等級低的人必須用白色的棋子。每個人最多隻能用一次黑色的棋子和一次白色的棋子。爲增加比賽的可觀度,觀衆希望K場對弈中雙方的等級差的總和最小。
比如有7個選手,他們的等級分別是30,17,26,41,19,38,18,要進行3場比賽。最好的安排是選手2對選手7,選手7對選手5,選手6對選手4。此時等級差的總和等於(18-17)+(19-18)+(41-38)=5達到最小。
輸入輸出格式
輸入格式:
第一行兩個正整數N,K
接下來有N行,第i行表示第i+1個人等級。
[數據規模]
在90%的數據中,1≤N≤3000;
在100%的數據中,1≤N≤100000;
保證所有輸入數據中等級的值小於100000000,1≤K≤N-1。
輸出格式:
在第一行輸出最小的等級差的總和。
輸入輸出樣例
輸入樣例#1:
7 3
30
17
26
41
19
38
18
輸出樣例#1:
5
這道題目看上去沒有任何思路,但是仔細思考,發現這題其實可以用貪心的方法,每次取最小的和然後累加,但是這樣暴力枚舉的時間複雜度異常高,果斷想到小根堆,可是時間複雜度還在O(n^2+nlog2(n))。再想想還能怎麼優化???如果把所有的數排序,然後兩兩作差(爲什麼成立???你問我?其是很簡單!),而它的成立性不言而喻,因爲如果排序後兩兩的差會比其他的大,這顯然不成立,因爲他們兩個數最靠近!!!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<iostream>
using namespace std;
priority_queue<int>q;
int a[100010];
struct node{
int u,v,w;
}e[100010];
int f[100010];
int gi(){
char c=getchar();int f=1,sum=0;
while((c>'9' || c<'0') && c!='-')
c=getchar();
if(c=='-'){f=-1;c=getchar();}
while(c>='0' && c<='9'){
sum=sum*10+c-'0';
c=getchar();
}
return f*sum;
}
int find(int x){
if(f[x]!=x)f[x]=find(f[x]);
return f[x];
}
void join(int x,int y){
x=find(x);y=find(y);
if(x!=y)f[y]=x;
}
int main(){
int i,j,k,n,m;
n=gi();k=gi();
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
for(i=1;i<n;i++)
q.push(a[i]-a[i+1]);
int ans=0;
for(i=1;i<=k;i++){
ans-=q.top();
q.pop();
}
printf("%d\n",ans);
return 0;
}