Skip to main content
Original232 words1 min

题解:P11462 huaijiao 要加学

Summary

共 m 天可安排学习,每门课程学一天带来固定收益、且最多有效学习若干天,求总收益的最大值。把收益整理为每门课的单日收益等于其价值除以天数上限,于是按单日收益从大到小排序,贪心地对每门课尽量多学,直到用完自身上限或剩余天数耗尽,累加收益。时间复杂度 O(n log n)。

解题思路​

整理:

W=∑i=1n(wi×ci)=∑i=1n(min⁡(1,xiki)×100×ci)=100∑i=1n(min⁡(ki,xi)×ciki)\begin{aligned} W & =\sum_{i=1}^n(w_i\times c_i) \\ & =\sum_{i=1}^n\left(\min\left(1,\frac{x_i}{k_i}\right)\times 100\times c_i\right) \\ & =100\sum_{i=1}^n\left(\min(k_i,x_i )\times\frac{c_i}{k_i}\right) \end{aligned}

可以发现,第 ii 门课程每学一天的收益是 ciki\frac{c_i}{k_i},且最多可学 kik_i 天。为了最大化总收益,应优先选择收益较高的课程。

因此,可以按 ciki\frac{c_i}{k_i} 从大到小排序,然后贪心地选择每门课程最多学习 x=min⁡(ki,m)x=\min(k_i, m) 天,并更新剩余天数 m←m−xm\gets m-x。

参考代码​

518 Bcpp
#include <bits/stdc++.h>
using namespace std;

using ll=long long;
const int N=1005;
struct Node
{
int c,k;
}a[N];
bool cmp(const Node &u,const Node &v)
{
return u.c*v.k>v.c*u.k;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i].c;
for(int i=1;i<=n;i++)cin>>a[i].k;
sort(a+1,a+n+1,cmp);
double ans=0;
for(int i=1;i<=n;i++)
{
int x=min(m,a[i].k);
ans+=x*100.0/a[i].k*a[i].c;
m-=x;
}
cout<<fixed<<setprecision(4)<<ans<<'\n';
return 0;
}