c904 - 天龍國的蜜蘋果
題目描述
題目要求從 N 個蘋果中,針對 M 個不同的 K 值,每次選出 K 個蘋果,使得選出的蘋果的單位重量售價(售價總和除以重量總和)最大化,並輸出對應的 K 值下的最大單位重量售價,精確到小數點後兩位。
解題思路
本題的核心思想是利用二分搜尋來尋找最大單位重量售價。對於每個 K 值,我們定義一個函數來計算給定單位重量售價下,可以選取的蘋果數量。然後,我們在可能的單位重量售價範圍內(從 0 到所有蘋果的最大售價)進行二分搜尋,直到找到滿足條件的最大單位重量售價。
具體步驟如下:
- 對於每個 K 值,定義一個二分搜尋函數
bs(min, max, k, n)。 - 在二分搜尋中,計算一個中間值
m,代表假設的單位重量售價。 - 對於每個蘋果,計算其在單位重量售價為
m時的“價值”:b[i] = a[i][1] - m * a[i][0]。 - 將所有蘋果的“價值”排序。
- 選擇價值最高的 K 個蘋果,計算其總價值。
- 如果總價值大於等於 0,則說明
m可能過小,將搜尋範圍調整到[m, max]。 - 否則,說明
m過大,將搜尋範圍調整到[min, m]。 - 重複步驟 2-7,直到找到滿足條件的最大單位重量售價。
複雜度分析
- 時間複雜度: O(M * N * log(N) * log(max_v)),其中 M 是 K 值的數量,N 是蘋果的數量,log(N) 是排序的複雜度,log(max_v) 是二分搜尋的複雜度,max_v 是蘋果的最大售價。
- 空間複雜度: O(N),主要用於儲存蘋果的重量和售價以及計算中間價值的
b陣列。
程式碼
#include <iostream>
#include <algorithm>
using namespace std;
double a[1000][2]={0},b[1000]={0};
double bs(double min,double max,int k,int n){
double m=(max+min)/2,sum=0;
if(max<min)
return m;
for(int i=0;i<n;i++)
b[i]=a[i][1]-m*a[i][0];
sort(b,b+n);
for(int i=0;i<k;i++)
sum+=b[n-i-1];
if(sum>=0)
return bs(m,max-0.0001,k,n);
return bs(min+0.0001,m,k,n);
}
int main(){
int N,M,K;
double max=0;
cin >> N >> M;
for(int i=0;i<N;i++){
cin >> a[i][0] >> a[i][1];
max+=a[i][1];
}
for(int i=0;i<M;i++){
cin >> K;
printf("%.2f\n",bs(0,max,K,N));
}
}