2020杭电多校第一场 hdu6759 Leading Robots

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=6759

题目大意

有 N 个机器人赛跑 , 第 i 个机器人初始速度为0 , 加速度为ai , 位置为 bi

现在所有机器人将开始行动 , 问有多少个机器人可以任意时刻当上第一

解题思路 

以 0 点为初始点, 那么第 i 个机器人行动了 t 秒后的位置为 $S_{i}=\dfrac{1}{2}a_{i}t^{2}+b_{i}$

我们令 y = Si , x = 1/2t^2 , ki = ai , di = bi

那么第 i 个机器人的运行轨迹就可以转换为一元一次方程 yi = ki * x + di

如下图

那么什么样的运动轨迹可以在某个时刻成为第一名的呢

不难发现 , 我们以二维的视角从上往下看 , 能看到的直线对应的机器人则有机会成为第一

再仔细观察 , 又可发现↓

对于一条直线C, 若存在一条斜率比它大的直线A,和斜率比它小的直线B

且 AC 的交点在BC的横坐标上的左边(对应下图中)蓝点和绿点 , 则直线C就会被 “覆盖”

所以我们可以按照斜率从大到小排序 , 用单调栈维护

先将斜率最大的A入栈  , 然后将次大的C入栈 , 然后判断当前直线 AC 的交点是否会在 BC的左边

在则弹出 C 进行下轮判断 , 直到不在或者栈中只剩 A  

最后栈内剩余的元素则是可以从上帝视角可以看到的直线个数

当然题目还有些细节要处理 : 

①、上帝视角可以看到的直线可能是位于 X 的负半轴的 , 而 t^2 是大于等于 0 的

这种情况我们只要加入一条斜率为负数 , 经过原点的直线即可 ( 答案个数 = 最后栈的大小 - 1)

②、题目可能存在两条重合的直线 , 这种情况按题目的意思谁都不能成为唯一的第一

所以对于每条直线我们要判断一下它被是否有重合

update :

为了方便读者观看我在赛后优化了代码 , 减少了一部分不要的语句导致除了点小锅

至于读入读反了能过也是神奇 hh

其中为了处理细节①所加入的直线应该满足的条件为

①、斜率为负数

②、截距取其它直线截距的max(要覆盖掉其它直线的负半段)

感谢 @AKDA 提出的问题 , 感谢@Overstars给出的hack数据

AC_Code

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define int long long
using namespace std;
#define ld long double
const int N = 5e5 + 10;
const ld eps=1e-20;
struct node
{
    ld k , b;
    int id , w;
} li[N];
int sta[N << 1] , top;
bool cmp(node t1 , node t2)
{
    if(t1.k == t2.k) return t1.b > t2.b;
    return t1.k > t2.k;
}
ld get(int x,int y)
{
    return (li[x].b - li[y].b) / (li[y].k - li[x].k);
}
map<pair<int , int> , int>mp;
signed main()
{
    ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
    int t;
    cin >> t;
    while(t --)
    {
        mp.clear();
        int n ;
        cin >> n;
        int cnt = 0 , ans = 0 , ma = -1;
        rep(i , 1 , n)
        {
            int k , b;
            cin >> b >> k;
            ma = max(ma , b);
            pair<int , int> now = make_pair(k , b);
            if(!mp[now])
            {
                mp[now] = ++ cnt;
                li[cnt].k = k , li[cnt].b = b;
                li[cnt].id = cnt , li[cnt].w = 1;
            }
            else li[mp[now]].w ++;
        }
        n ++;
        li[n].k = -1 , li[n].b = ma , li[n].w = 0;
        sort(li + 1 , li + 1 + n , cmp);
        sta[1] = 1 , top = 2;
        rep(i , 2 , n)
        {
            if(li[i].k == li[i - 1].k) continue ;
            while(top >= 3 && get(sta[top - 1] , sta[top - 2]) - get(sta[top - 1] , i) <= eps) top --;
            sta[top ++] = i;
        }
        rep(i , 1 , top - 1) if(li[sta[i]].w < 2) ans ++ ;
        cout << ans - 1 << '\n';
        rep(i , 1 , n) li[i].k = li[i].b = li[i].id = li[i].w = 0;
    }
    return 0;
}
posted @ 2020-07-21 22:33  GsjzTle  阅读(821)  评论(11编辑  收藏  举报