插队
链接: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 1e91≤n≤1e5,0≤ai≤1e9
输出描述:
输出包括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开始向前找,更加节约时间。
浙公网安备 33010602011771号