Leading Robots | 贪心 单调栈


题意:机器人比赛跑步,知道了初始位置,和加速度,求有多少机器人能成为领头羊(在某一刻跑到第一名,不能并列)
思路:因为知道了加速度,所以很容易知道,当加速度最快的成为了领头羊,其他机器人就没机会了,并且,当一个机器人在初始位置和加速度都比前面的机器人小的话,也不可能。根据这两个特性,我们就可以通过将机器人的初始位子从大到小进行比较,而在后面的机器人只有加速度比在他之前所有的机器人都要大,才有机会成为零头羊,再利用栈查看当前机器人能否在前一个机器人成为领头羊之前超越他,如果可以,那前面的机器人就不是领头羊,具体看代码

点击查看代码




int sgn(double x) // 因为是double,需要用到精度
{
    if (fabs(x) < ep)
        return 0;
    if (x > 0)
        return 1;
    return -1;
}

struct point
{
    ll a, p;
} a[N];
int cmp(point a, point b) // 按照位置进行排序
{
    if (a.p == b.p)
        return a.a > b.a;
    return a.p > b.p;
}
vector<int> v;
int n;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n;
        a[n + 1].a = a[n + 1].p = 0;
        for (int i = 1; i <= n; i++)
            cin >> a[i].p >> a[i].a;
        sort(a + 1, a + 1 + n, cmp);
        // 加速度最大的那个人肯定是最后的赢家,距离最远的是最先是领头羊的机器人 
        ll ma = a[1].a;//ma就相当于一个标准,因为是按位置进行比较,所以只有大于mx的速度才会成为领头羊 
        stack<PII> s; // 
        s.push({1, 1});//第一个数是机器人i的下表,第二个是在i之前最快成为领头羊机器人的下表 
          ll ma = a[1].a;
        for (int i = 2; i <= n; i++)
        {
            if (a[i].a <= ma)
                continue;
            // 如果加速度小于且本来位置比较靠后的话是不可能超过前面那个人的
            
            ma = a[i].a;
            //5 1 4 2 1 5 
            int y = 1; // y储存的是在i之前的超过最后一个机器人的最快机器人的下标
            
            //由于栈存储的机器人的位置都比机器人i大,所以如果机器人i成为领头羊的时间比他们小,那前面的机器人就没机会了,压出栈 
            while (!s.empty())
            {
                PII from = s.top();
                int o = from.first;
                int r = from.second;
                //为什么会需要r呢 ,来看个例子
                 //为什么要存第二个呢,其实就是判断后面的机器人能否在o超越r之前把他给超过了,这样o就永远不可能成为领头羊,就压出栈 ,来看个例子 
				//i=1 10 2 i=2 8 3 i=3 5 4 i=4 3 5
				//i=1,首先栈先存入(1,1) 
				// i=2, 栈中只有1,直接存入(2,1)
				//i=3, 利用公式得出,机器人3不能再机器人2超越机器人1前超过机器人2,所以机器人2会成为领头羊(但如果t1<t2,就说明机器人3会再机器人2超越机器人1前超过机器人2,那就给2踢出去)
				//i=4 只要最后一个机器人的加速度大于前面所有机器人的速度,那他就是最后的领头羊,直接入就好了 
                double t2 = sqrt(2.0 * (a[i].p - a[o].p) / (a[o].a - a[i].a)); // 超过的时间就是距离除以速度差
                double t1 = 0;
                if (o != r)
                    t1 = sqrt(2.0 * (a[o].p - a[r].p) / (a[r].a - a[o].a));
                if (sgn(t2 - t1) <= 0)
                // 利用精度进行比较(感觉我就cuo在这里) 
                {
                    y = r;
                    s.pop();
                    // 如果机器人i在o超越r之前超越了他,说明前一个永远不会是领头羊,此时r就是在i之前最快成为领头羊的机器人,所以y=r 
                }
                else
                {
                    y = o;//如果机器人i不能在o超越r之前超越了他,那o对于i来说就是最快成为领头羊的机器人,所以y=o 
                    break;
                }
            }
            s.push({i, y});//因为上面有判断加速度,所以到这一步的机器人都有成为领头羊的可能,直接入 
        }
        int ans = s.size();
        while (!s.empty())
        {
            PII from = s.top();
            s.pop();
            int y = from.first;
            if (a[y].a == a[y + 1].a && a[y].p == a[y + 1].p) // 判断是否有一起超过的情况
                ans--;
        }
        cout << ans << "\n";
    }
}


posted @ 2025-03-13 20:38  台州第一深情  阅读(21)  评论(0)    收藏  举报