397 字
2 分钟
Luogu-P1570-题解
P1570 题解
题目分析
刚开始做这道题可能没什么思路,所以我们先从式子入手:
假设存在最优解ans:
转化得
移项得
可见,当式子的结果趋向 时,ans是最优解。
所以我们可以设
显然,是一个一次函数,具有单调性。这个时候就会想到可以使用二分答案来解决这个问题。
既然使用二分答案来解决,首先应该考虑边界问题,这道题的边界比较好设定,左端点显然为,而右端点的设定,我们秉持着不怕大只怕小的原则,可以将其设定为。
然后考虑check函数问题,思考之后可以发现,我们只需要判断在ans确定的情况下,最优的取法。所以考虑贪心,把每种调料的计算出来,从小到大排序之后取前个调料的一次函数值并累加。计算之后的数值与零相比较,如果小于零的话,说明还可以更大,反之则应该更小。
到这里,这道题目就ac了,要注意好细节问题。
#include<bits/stdc++.h>using namespace std;#define int long longint n,m,cnt=0;;struct coffee{ int v,c; double tot;}a[10010];void read(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i].v;cnt+=a[i].v; } for(int i=1;i<=n;i++){ cin>>a[i].c; }}bool cmp(coffee a,coffee b){ return a.tot<b.tot;}bool check(double x){ for(int i=1;i<=n;i++){ a[i].tot=x*a[i].c-a[i].v; } double sum=0; sort(a+1,a+n+1,cmp); for(int i=1;i<=m;i++){ sum+=a[i].tot; } return sum<=0;}double search(){ double l=0,r=cnt; while(r-l>=1e-5){ double mid=(l+r)/2.0; //cout<<mid<<endl; if(check(mid)){ l=mid; } else{ r=mid; } } return l;}signed main(){ read(); double ans=search(); printf(“%.3lf”,ans); return 0;}
Luogu-P1570-题解
https://blog.introl.top/posts/luogu-p1570-题解/