弹珠(贪心+二分)

Posted linzeli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了弹珠(贪心+二分)相关的知识,希望对你有一定的参考价值。

https://www.luogu.org/problemnew/show/T32708

这道题是校模拟的一道题,

本来的朴素想法是贪心,当时得了40分,但是程序很乱

第二次修改了数据结构,程序变得清爽许多,但是分数没有改变,后来手动加了一个特判多了二十

第三次按照正解的思路但是仍然出了一点小bug,最后成功

首先用贪心的时候要做一个简单的正确性证明,可以举几个特殊的例子,

正确的做法应该是二分然后不断逼近,技术分享图片

 

标程

//原本是说b总和除以w总和的最大值,将其转换为b-x*w,
//算其余下多少,不断接近
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct date{
int wz,bz;
float v;
}g[1200];
int w[6000],b[6000];//b是美丽值,w是重量
float ps[1200];
int n,m,k;
int w2,b2;
float v2;
int ok(float x){
for(int i=1;i<=m;i++)ps[i]=(float)(g[i].bz-x*g[i].wz);
sort(ps+1,ps+1+m);//n,m错
// for(int i=m;i>=1;i--)
// cout<<ps[i]<<" ";
float tot=0;
for(int i=m;i>=m-k+1;i--)tot+=ps[i];//n,m错
return tot>=0;
}
void solve(){
float l=0,r=1500;
while((r-l)>1e-3){//应用二分计算
float mid=(l+r)/2.0;
if(ok(mid))l=mid+1e-3;
else r=mid-1e-3;
}
printf("%.2f",(l+r)/2.0);
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
int x;
for(int i=1;i<=m;i++){
scanf("%d",&x);
while(x){
g[i].wz+=w[x];
g[i].bz+=b[x];
scanf("%d",&x);
}
}
solve();
return 0;
}
/*学姐的更优雅的二分写法
float l=0,r=1500;
for(int time=0;time<=100;time++){
float mid=(l+r)/2.0;
if(ok(mid))l=mid;
else r=mid;
}
printf("%.2f",(l+r)/2.0);





























































以上是关于弹珠(贪心+二分)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2453维护队列/bzoj2120数颜色 分块+二分

BZOJ2453: 维护队列&&BZOJ2120: 数颜色 二分+分块 双倍经验

P1537 弹珠

P1537 弹珠 布尔背包

超大背包(二分+贪心)

Codeforces 825D 二分贪心