hdu4393 Throw nails【优先队列&&贪心&&模拟】

12 篇文章 0 订阅
8 篇文章 0 订阅
题目大意:

给你n个人,他们在进行一场自行车竞速比赛,每个人在第1s时走Fi米,以后每秒走Si米,一个小孩在仍钉子破坏比赛,每秒他都选最靠前的那个人,如果有多个人,选编号最小的那个,问你这些人依次被破退出比赛的顺序。(1 <= n <= 50000)(0 <= Fi <= 500)(0 < Si <= 100)

解题思路:

开始时只看到1 <= n <= 50000,一直在想怎么用数据结构做。
后面发现0 <= Fi <= 500,0 < Si <= 100,这就成水题了。

先说最水的做法。
很容易想到如果大家Fi都为相同,就只与速度有关了,所以关键在于讨论Fi不同所带来的影响
注意0 <= Fi <= 500,所以最多当501秒时,Fi的影响就完全消失了……所以前501秒暴力模拟,以后直接比速度即可……是不是感觉智商被强奸了……

再说说有点逼格的做法。
刚刚的做法是消除了Fi的影响,现在想想消除速度的影响。
假设速度都一样,那就只与Fi有关了,又注意到0 < Si <= 100,所以可以开101个优先队列,把速度相等的选手都放在一个队列里,按Fi排序,以后每次把101个队首提出作比较即可。
其实这样的做法有点像NOIP2016的“蚯蚓”一题。都利用了单调性这一特点。

贴了份优先队列的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=50005;
int T,n;
priority_queue<pair<int,int> >q[101];

int main()
{
    //freopen("lx.in","r",stdin);
    T=getint();
    for(int C=1;C<=T;C++)
    {
        printf("Case #%d:\n",C);
        n=getint();
        for(int i=0;i<=100;i++)
            while(!q[i].empty())q[i].pop();
        for(int i=1;i<=n;i++)
        {
            int f=getint(),s=getint();
            q[s].push(make_pair(f,-i));
        }
        for(int t=1;t<=n;t++)
        {
            int id=0,ans=-1;
            for(int i=0;i<=100;i++)
            {
                if(q[i].empty())continue;
                int d=q[i].top().first+(t-1)*i;
                int u=-q[i].top().second;
                if(ans<d||ans==d&&u<-q[id].top().second)
                    ans=d,id=i;
            }
            if(t==n)printf("%d\n",-q[id].top().second);
            else printf("%d ",-q[id].top().second);
            q[id].pop();
        }
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值