Codeforces 319B Psychos in a Line 题解 [ 绿 ] [ 单调栈 ] [ 动态规划 ] [ adhoc ]

Psychos in a Line:很好的单调栈优化 dp 题!

观察

我们先观察,一个精神病人会一直杀到什么时候。显然,会杀到右边第一个比他大的精神病人那里,然后他就杀不动了。

因此我们可以从右往左考虑,算出左边的精神病人杀掉这个精神病人后左边的人的答案是什么。假设左边的人目前已经刀了 \(x\) 个人,被杀的人目前会\(y\) 个人。如果左边杀这个人的时候这个人该杀的还没杀完,那么左边人就要接着这个人继续把该杀的杀掉,又因为它们刀人是同步进行的,所以此时左边的人目前刀掉的人数取 \(\max(y,x+1)\)

于是,我们定义 \(dp_i\) 表示第 \(i\) 个人目前会刀几个人,然后 \(O(n^2)\) 转移即可。

优化

但是这样显然无法通过,考虑如何优化。

因为一个人会被他左边第一个比他大的人杀掉(不一定最后真的是被他杀的,如果他杀这个人之前就被杀了,那么情况还是等价的,不影响计算),所以我们从右到左维护一个单调栈,维护右边的最大值。在一个元素入栈的时候,只取弹出的元素转移即可。

时间复杂度 \(O(n)\),主要还是理解一个人先钦定被左边第一个比他大的人杀,之后再动态调整,不影响最终答案的类似反悔贪心的思想

代码

#include <bits/stdc++.h>
using namespace std;
int n,a[100005],dp[100005],tp=0,s[100005],ans;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=n;i>=1;i--)
    {
        int res=0;
        while(tp&&a[s[tp]]<a[i])res=max(res+1,dp[s[tp--]]);
        s[++tp]=i;
        dp[i]=res;
        ans=max(dp[i],ans);
    }
    cout<<ans;
    return 0;
}

来源链接:https://www.cnblogs.com/zhr0102/p/18653340

请登录后发表评论

    没有回复内容