1 条题解
-
1
来自面条老师 题目翻译大意:
可以操作若干次,每次可以按序将一个数推进已有的栈或新建的一个栈,或者将一个数取出,求最大推进的数的最大前缀使得取出的数有序。 因为是栈,而且需要按序取出,那么我们有一个贪心的策略,假设我们当前有 n 个栈,这 n 个栈都必须满足自上向下从大到小,并且对于任意的编号为 i 的栈(编号越小表示越靠左,i⩾1),需满足 i+1的栈顶元素大于 i 的栈底元素。 对于插入第 i 个数: 如果这个数比最后一个栈的栈底元素还要大,则新建一个栈; 如果这个数比之前取出的数的最大值要小,则说明之后无法有序,则答案为 i-1(因为这样我们可以从左到右将剩下的栈的元素依次取出且保证有序); 否则将这个数插入栈中,先二分查询在哪个栈内,然后将栈中所有比这个数大的数弹出,再推进栈中。
很有道理啊(喜)
这题看来是用贪心没跑了,可惜那时候我没想出来QAQ
读后感
这题就是建立一个栈的体系并且让每个栈里面都从小到大排列并且每两个栈之间都必须保证右边的栈所有数字都大于左边的栈的所有数字这样就可以保证从最左边取时就可以符合题意 引言里面的道理:对于此题,假如说现有栈的所有数字都小于目前正在处理的数据,那么一定会新建栈 当处理的数据被插入栈的时候,一定也会保持栈原有的规律
引言的二分我倒是没有使用,但是实现效果是一致的
对于第一点
if( a[ i ] > s[ st ][ 0 ] ) { st ++ ; s[ st ].push_back( a[ i ] ) ; }
第二点
else if( a[ i ] < maxn ) { cout << i - 1 ; return 0 ; }
第三点
else { for( int j = 1 ; j <= st ; j ++ ) { if( a[ i ] < s[ j ][ 0 ] ) { int k = s[ j ].size() - 1 ; while( a[ i ] > s[ j ][ k ] ) { maxn = max( maxn , s[ j ][ k ] ) ; s[ j ].pop_back() ; k -- ; } s[ j ].push_back( a[ i ] ) ; break ; } } }
几个问题(做题时想到的) 为什么有break:减少循环次数减少时间,也可以防止继续判断改变数据
大于和小于换成≥和≤可以吗:题目没有重复数据,所以一定没有相等的情况,加不加随意
总体实现代码
#include<bits/stdc++.h> using namespace std; int n , a[ 100001 ] , st = 1 , maxn = INT_MIN ; vector<int> s[ 100001 ] ; int main() { ios::sync_with_stdio( 0 ) ; cin.tie( 0 ) ; cin >> n ; for( int i = 1 ; i <= n ; i ++ ) cin >> a[ i ] ; s[ 1 ].push_back( a[ 1 ] ) ; for( int i = 2 ; i <= n ; i ++ ) { if( a[ i ] > s[ st ][ 0 ] ) { st ++ ; s[ st ].push_back( a[ i ] ) ; } else if( a[ i ] < maxn ) { cout << i - 1 ; return 0 ; } else { for( int j = 1 ; j <= st ; j ++ ) { if( a[ i ] < s[ j ][ 0 ] ) { int k = s[ j ].size() - 1 ; while( a[ i ] > s[ j ][ k ] ) { maxn = max( maxn , s[ j ][ k ] ) ; s[ j ].pop_back() ; k -- ; } s[ j ].push_back( a[ i ] ) ; break ; } } } } cout << n ; return 0; }
- 1
信息
- ID
- 1954
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 1
- 标签
- (无)
- 递交数
- 45
- 已通过
- 34
- 上传者