训练联盟第一场E-Early Orders-单调栈,思维

题目大意:

给你一个长度为 n n n的序列。让你选出 k k k个数,使得其字典序最小,且 [ 1 , k ] [1,k] [1,k]每个数恰好出现一次。

题目思路:

这题有一个弱化版:https://leetcode-cn.com/problems/remove-k-digits/

如果没有第二个限制,这题就是上面那题。所以可以想象这题也能使用单调栈做。

假设前面已经选了 k k k个数。现在新增一个从未出现过的数 x x x。如果最后一个数比 x x x大并且之后还有这个数,则可以删除这个数,并且保证答案仍然存在。往复这个过程即可.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define vi vector<int>
#define vl vector<ll>
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
int a[maxn] , bk[maxn] , ok[maxn];
int main()
{
    
    
    ios::sync_with_stdio(false);
    int n , k;
    cin >> n >> k;
    for (int i = 1 ; i <= n ; i++){
    
    
        cin >> a[i];
        bk[a[i]]++;
    }
    stack<int> s;
    for (int i = 1 ; i <= n ; i++){
    
    
        if (!ok[a[i]]){
    
    
            while (s.size() && s.top() > a[i] && bk[s.top()]) {
    
    
                ok[s.top()] = false;
                s.pop();
            }
            ok[a[i]] = 1;
            s.push(a[i]);
        }
        bk[a[i]]--;
    }
    vi ans;
    while (s.size()) ans.pb(s.top()) , s.pop();
    reverse(ans.begin(),ans.end());
    for (auto g : ans) cout << g << " ";
    cout << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/114496838