P4653 [CEOI2017] Sure Bet
P4653 [CEOI2017] Sure Bet
题目翻译:
我们可以选取任意数量的灯泡,其中灯泡有两种,每一个灯泡都有一个价值,而每取一个灯泡都会消耗一个价值,而我们要求的是,最后若只计算一种种类的灯泡的话,那获得价值较小的最大值。
思路分析:
我们根据题意可已发现我们的目标:若所选第一种的灯泡的总价值为\(a\),第二种为 \(b\)。总共取了 \(k\) 个灯泡,那最终答案就是 \(min(a-k,b-k)\) 我们就是要找一个方案使这一个的值最大。可以很明显发现以下性质:
- 最后求得的 \(a\) 和 \(b\) 差要尽可能少,因为反正都是找最小值,那大的就没必要再花费价值去选了。
- 如果一个灯泡的价值越大,就越有必要选,因为最后获得价值是更高的。所以一定是从大往小选。
因此我们只需要贪心一下,从大往小选,其中还要尽量满足两种类的价值不相差太大即可
实现:
1.先将价值从大到小排序
2.在维护一个 \(suma\) \(sumb\),来储存当前选到价值
3.若 \(suma>sumb\) 那就选第二类的
4.反之就选第一类的
5.每次选择都维护最大值 \(ans\) 即可
完整代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
double a[N],b[N];
int visa[N],visb[N];
bool cmp(double x,double y){
return x>y;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf%lf",&a[i],&b[i]);
}
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1,cmp);
double suma=0,sumb=0,ans=0;
for(int i=1,j=1;i<=n && j<=n;){
suma+=visa[i]?0:a[i];
sumb+=visb[j]?0:b[j];
visa[i]=1;
visb[j]=1;
ans=max(min(suma-i-j,sumb-i-j),ans);
if(suma<=sumb)i++;
if(sumb<=suma)j++;
}
printf("%.4lf",ans);
}
本文作者:XichenOC
本文链接:https://www.cnblogs.com/XichenOC/p/18682402
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步