题目描述
给定长度为 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 ":"%d ",ans[i]); 26 } 27 28 return 0; 29 }