勇者是一個強迫症,而且又很摳門(雖然他有錢),每次點的菜系一個也不能少。
每次都問飯店老闆第k小的組合是什麼,店老闆答錯了了勇者還會發飆。
於是店老闆撂下一句mmp,然後找到了路由器。
題目描述
又到吃飯時間,Polo 面對飯堂裏琳(fei)琅(chang)滿(keng)目(die)的各種食品,又陷入了痛苦的抉擇中:該是吃手(jiao)打肉餅好呢,還是吃豆(cai)角(chong)肉片好呢?嗯……又不是天秤座怎麼會醬紫呢?
具體來說,一頓飯由M 個不同的部分組成(葷菜,素菜,湯,甜品,飲料等等),Polo 要在每個部分中選一種作爲今天的午飯。俗話說的好,永遠沒有免費的午餐,每種選擇都需要有一定的花費。長者常常教導我們,便宜沒好貨,最便宜的選擇估計比較坑爹,可囊中羞澀的Polo 還要把錢省下來給某人買生日禮物,這該怎麼辦呢?
於是一個折中方案出來了:第K 便宜的組合要花多少錢?這就要靠你了。
輸入
第一行兩個數M,K,含義如上所述。
接下來M 行,先是一個整數Ai,表示第i 個部分有多少種選擇。接下來用空格分開的Ai 個整數表示每種選擇的價格。
輸出
一行一個整數表示答案。
樣例輸入
2 2
2 1 3
2 2 2
樣例輸出
3
提示
【樣例解釋】
最便宜的選擇是第一部分選擇1 塊錢的,第二部分選擇2 塊的。但由於第二部分裏2 塊錢有兩種不同的選擇,所以第二便宜的總花費仍然是3 塊。
好的雖然很不想寫優先隊列……但這題手寫優先隊列……臣妾實在做不到(一個小時奮鬥無果,只好去自學優先隊列函數了TAT)
那麼先說優先隊列函數
定義:隊列裏的元素按照重要性動態的排序就是優先隊列。無特殊說明,元素數字越大,越重要。
使用:先#include然後priority_queue q;(類型可改)
函數:q.push(i)隊列加入一個數i;
q.pop()彈出最重要的元素;
n=q.top()最重要的元素;
q.size()元素個數;
好知道這些就夠了。
那麼這個魔(題)法(解)其實很簡單:
1.對數據由小到大排序。
2.數組dui[]表示從上到下依次累計和,永遠保留最小的k個。
3.輸出第k個。
優化:
1.只需要k個數,所以m=1時只需要在dui裏面存min(a[1],k)即可。
2.由第1可知當dui[p]+b[i][j]大於了隊列最大值,那麼後面所有的dui[p]+b[i][j]一定大於最大值,所以直接跳出。(正確性不予證明)
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int a[11];
long long b[11][500001];
long long dui[1000000];
priority_queue<long long> q;
int main(){
int m,k;
scanf("%d%d",&m,&k);
for(int i=1;i<=m;i++){
scanf("%d",&a[i]);
for(int j=1;j<=a[i];j++){
scanf("%lld",&b[i][j]);
}
sort(b[i]+1,b[i]+a[i]+1);
}
int tot=min(a[1],k);
for(int i=1;i<=tot;i++){
dui[i]=b[1][i];
}
for(int i=2;i<=m;i++){
long long maxn=21000000000000;
for(int j=1;j<=a[i];j++){
for(int p=1;p<=tot;p++){
if(dui[p]+b[i][j]>maxn){
break;
}
if(q.size()<k){
q.push(dui[p]+b[i][j]);
if(q.size()==k){
maxn=q.top();
}
}else{
if(dui[p]+b[i][j]<maxn){
q.pop();
q.push(dui[p]+b[i][j]);
maxn=q.top();
}
}
}
}
tot=0;
while(!q.empty()){
tot++;
dui[tot]=q.top();
q.pop();
}
for(int p=1;p<=tot/2;p++){
long long t;
t=dui[p];
dui[p]=dui[tot-p+1];
dui[tot-p+1]=t;
}
}
printf("%lld",dui[k]);
return 0;
}