17-比赛1 A - Weak in the Middle (栈)

题目描述

给定长度为 N 的序列 A。每天,序列 A 中所有比两侧元素都小的元素都会消失。
对于原序列中所有元素,请求出它会在第几天之后消失(天数从 1 开始计算),或者指出它不
会消失。

数据范围

1 ≤ T ≤ 1, 000
1 ≤ N ≤ 1e5
1 ≤ Ai ≤ 1e9

输入格式

输入的第一行包含一个整数 T,代表测试数据的组数。接下来是 T 组数据。
每组数据的第一行包含一个整数 N。第二行包含 N 个整数 A1, A2, . . . , AN。

输出格式

对于每组数据,输出一行,包含 N 个整数。第 i 个整数代表第 i 个元素在第几天消失;如果
它不会消失,则应当为 0。

样例输入

1
6
3 2 5 4 1 7

样例输出

0 1 0 2 1 0

========================================================================================================================================================

关键词 : 栈 

当时比赛未解决的题目

学长的题解 :

因为需要计算出在第几天被删除,暴力的做法必然会导致超时;

因此可以用栈来简化,求出最后剩下的;

设当前处理的数为 a[i],栈顶元素为 st[top] 

如果 st[top]-1>st[top]<a[i];

则 删除栈顶元素 将 a [i] 压入栈

被删除的天数则考虑反证法,某一个数a[i]很大  , 多次参与 删除,则最后 一个因为a[i] 被删除的数的天数一定是 max(a[i]参与过的次数,该数参与过的次数) + 1 ,a[i] 参与的次数又发生变化。 

========================================================================================================================================================

代码实现如下

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1e5 + 10;
 4 
 5 int ans[N],a[N],st[N],Max[N],top;
 6 
 7 int main()
 8 {
 9     int T; scanf("%d",&T);
10     while(T--)
11     {
12         int n;
13       scanf("%d",&n);
14       for(int i = 1;i <= n ;++i) ans[i] = Max[i] = 0; top = 0; //初始化
15       for(int i = 1;i <= n ;++i) scanf("%d",a + i);
16       for(int i = 1;i <= n ;++i){
17         while(top>=2&&a[st[top]]<a[st[top-1]]&&a[st[top]] < a[i])
18         {
19             ans[st[top]] = max(Max[st[top-1]],Max[st[top]])+1;   //当前被删除的次数为max(前一位参与的次数,栈顶参与的次数)+1
20             Max[st[top-1]] = ans[st[top]];      //前一位参与了这次删除,次数变化
21             --top;
22         }
23         st[++top] = i;
24       }
25       for(int i = 1;i <= n;++i) printf(i==n?"%d\n":"%d ",ans[i]);
26     }
27 
28     return 0;
29 }

 

posted on 2018-07-28 15:16  短发控丶  阅读(141)  评论(0编辑  收藏  举报

导航