插队

链接:https://ac.nowcoder.com/acm/contest/11290/I
来源:牛客网

题目描述

万众瞩目的acm基地招新大会开始了。
基地的招新面试是排队进行的,但由于每个人都希望能早点加入基地,于是他们会插队。acmer之间的插队,当然会用编程能力说话。当某个人进行插队时,若在ta前面一位的同学编程能力不强于ta,ta会用能力(暴力)劝导(强迫)对方同意ta插队。若前面的同学能力强于ta,则ta可以送上一张大佬的签名进行贿赂而插队,但每个人只能有一张签名,所以这样的贿赂只能实现一次。
现在问你,对于每个人来说,在不考虑其他人插队的情况下,就仅有ta自己插队能够最终排到什么位置。

输入描述:

第一行包括一个整数nnn,代表参加acmacmacm基地招新面试的人数
第二行包括nnn个整数,第iii个aia_iai代表第一个人的能力值
1≤n≤1e5,0≤ai≤1e91 \leq n \leq 1e5,0 \leq a_i \leq 1e91n1e5,0ai1e9

输出描述:

输出包括nnn行,每行一个整数,第iii行的数sis_isi代表原队列的第iii个人最终能排在第sis_isi个位置,下标从1开始
#include<cstdio>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn=100010;
int a[maxn],f[maxn],ans[maxn];
stack<int> S;
int main()
{
    int n;
    S.push(0);
    scanf("%d",&n);
    a[0]=inf;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        while(a[S.top()]<=a[i]) S.pop();
        f[i]=S.top();
        if(f[i]==0)  {printf("1\n");ans[i]=1;}
        else{
            int k = (a[i] >= a[i - 1] && f[i] == f[i - 1]) ? ans[i - 1] - 1 : f[i] - 1;
            while(a[k]<=a[i]) k--;
            printf("%d\n",k+1);
            ans[i]=k+1;
        }
        S.push(i);
    }
    return 0;
}

题意即求 每个数 前面 比它大的 最近的 第二个数 的位置

用栈维护。每次ai和栈内元素比,比ai小的出栈,找到第一个比ai大的数。

再把ai(的下标)压栈。之后的数没有ai大,也就没必要和弹出的那些比了。

比for循环好的是啥?感觉要快。

 

ans[]是一点优化 不写这句:

            int k = (a[i] >= a[i - 1] && f[i] == f[i - 1]) ? ans[i - 1] - 1 : f[i] - 1;

 直接int k= f[i] - 1;可以过95%

 

如:。。。9 3 2 4 5,4和5的f都是9的下标(即第一个比他们大的数),那么两者都要跨过9,且4能到的位置5一定可以到。

5就可以从4的ans开始向前找,更加节约时间。

posted on 2022-03-10 16:01  衔白棋子的黑猫  阅读(105)  评论(0)    收藏  举报

导航