CF319B 疯子站队

1 CF319B 疯子站队

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

\(n\) 个疯子站成一排,每个疯子都被分配一个从 \(1\)\(n\) 的编号。在每一轮中如果疯子的编号大于右边挨着的疯子就会杀死右边的疯子,注意一个疯子有可能在一个步骤中杀死右边的疯子然后自己也被杀死。给出一排疯子的排列顺序,计算需要多少轮以后就没有疯子杀人了。

数据范围:\(1 ≤ n ≤ 10^5\)

3 题解

容易发现,某个被杀死的疯子一定是被其前面的值大于他的疯子所杀死的。更具体的,如果当前疯子位置为 \(y\),设在其左侧且最靠近 \(y\) 的大于当前疯子编号的一个疯子位置为 \(x\),那么在 \(x\)\(y\) 中间的所有疯子的编号明显小于 \(y\) 疯子的编号。也就是说,在这些疯子死亡前,\(y\) 疯子没有生命危险。那么 \(y\) 疯子死亡的轮数就是 \(x\)\(y\) 中所有疯子的死亡轮数最大值 \(+1\)。根据这个算法,我们可以建立一个单调栈,从栈底到栈顶递减。如果某一个当前枚举到的疯子编号比栈顶的疯子编号大,那么我们不停弹出栈顶的疯子,直到栈顶的疯子编号大于当前疯子。此时,我们所弹出的所有疯子中编号的最大值 \(+1\) 就是答案。

如果我们此时并没有弹出任何疯子,就意味着当前疯子的编号小于其正前面的疯子的编号。此时,当前疯子在第一轮就会死,\(f_i\) 就是 \(1\)。如果在弹出栈顶的疯子后,栈中没有任何疯子存在,那么当前疯子不会死,因为他肯定是当前编号最大的疯子。

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 1e5+10;
int n, top, ans, maxn;
int a[N], st[N], f[N];
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++)
    {
        maxn = 0;
        while (top && a[st[top]] < a[i]) maxn = max(maxn, f[st[top--]]);
        if (!top) f[i] = 0;
        else f[i] = maxn + 1;
        st[++top] = i;
        ans = max(ans, f[i]);
    }
    cout << ans;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-31 15:32  David24  阅读(193)  评论(0编辑  收藏  举报