【bzoj2328】[HNOI2011]赛车游戏

题目链接

Description

这里写图片描述

题解

从耗油量最少开始慢慢贪心地调整。
对于上坡,速度设为0,但是免不了耗油,这一部分的耗油先减掉。
对于下坡,速度在不耗油的前提下设到最大(但是不能超过vmax)。
对于平路,速度设为0。
然后我们用一个优先队列来维护这些线段,每次取出速度最小的段,如果它的速度和次小的速度一样就合并起来,否则将它的速度提升到和次小的速度一样,当然这是在油够用的前提下,如果油不够用就提到能提到的最高速率。
这样做直到用光油或者都打到vmax时结束。
看起来挺对的。。是吧?

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

typedef double db;

const db eps = 1e-9;

struct Node{
    db v, x;
    Node(){}
    Node(db a, db b){v = a, x = b;}
    bool operator < (const Node &a)const{
        return v > a.v;
    }
};
db a, b, vmax, f;
int n;
bool ok;
priority_queue<Node> q;

inline int fcmp(db x){
    if(fabs(x) < eps) return 0;
    else return x > 0 ? 1 : -1;
}
inline db sqr(db x){return x * x;}

void init(){
    scanf("%lf%lf%lf%lf%d", &a, &b, &vmax, &f, &n);
    db x, y, s, l;
    ok = true;
    for(int i = 1; i <= n; i++){
        scanf("%lf%lf", &x, &y);
        x /= 1000.0, y /= 1000.0;
        s = y / x; l = sqrt(sqr(x) + sqr(y));
        if(fcmp(s) > 0){
            f -= l * b * s;
            q.push(Node(0, l));
            if(fcmp(f) <= 0) ok = false;
        }
        else if(fcmp(s) < 0)
            q.push(Node(min(-s * b / a, vmax), l));
        else q.push(Node(0, l));
    }
}

void solve(){
    if(!ok){
        puts("IMPOSSIBLE");
        while(!q.empty()) q.pop();
        return;
    }
    q.push(Node(vmax, 0));
    Node u, v;
    db w;
    db ans = 0;
    while(fcmp(f) > 0 && !q.empty()){
        u = q.top(); q.pop();
        v = q.top();
        if(!fcmp(u.v - vmax)) ans += u.x / u.v;
        else if(fcmp(u.v - v.v)){
            w = f / (a * u.x);
            if(fcmp(u.v + w - v.v) >= 0){
                w = v.v - u.v;
                q.pop(); q.push(Node(v.v, u.x + v.x));
            }
            else{
                u.v += w;
                q.push(u);
            }
            f -= a * w * u.x;
        }
        else{
            q.pop();
            q.push(Node(v.v, u.x + v.x));
        }
    }
    while(!q.empty()){
        u = q.top(); q.pop();
        ans += u.x / u.v;
    }
    printf("%.5lf\n", ans);
}

void work(){
    int t; scanf("%d", &t);
    while(t--){
        init();
        solve();
    }
}

int main(){
    work();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值