Early Orders 数据结构 + 思维

Early Orders 数据结构 + 思维

题目大意:

给你一个序列,让你找一个字典序最小的子序列,要求这子序列是一个前k个数的全排列。

题解:

难度不太,冷静思考。

  • 先赋值 (l = 1)

  • 首先从后往前找,找到最大的 (r) ,使得 ([r,n]) 存在一个子序列是前 k 个数的全排列

  • 那么,接下来只要找 ([l,r]) 的最小值 (pos) 即可,然后将 (pos) 这个位置的值标记,表示已经用过,并赋值 (l = pos+1) ,更新 (r) ,从 (r) 往后找,一直找到一个点 (v) ,这个点的值没有被用过,而且是这个值的最后一个位置, (r = v)

  • 重复第二个步骤,知道找完位置。

我用的优先队列写的,写起来还是有点恶心,码量不大,要注意很多细节。

#include <bits/stdc++.h>
#define lson (id<<1)
#define rson (id<<1|1)
using namespace std;
const int maxn = 2e5+10;
typedef long long ll;
int a[maxn],vis[maxn];
vector<int>ans;
struct node{
    int id,d;
    bool operator<(const node&a) const{
        return a.d<d;
    }
};
priority_queue<node> que;
int last[maxn];
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        last[a[i]] = i;
    }
    int l = 1,r = n,cnt = 0;
    for(int i=n;i>=1;i--){
        if(vis[a[i]]) continue;
        cnt++,vis[a[i]] = true,r = i;
        if(cnt==k) break;
    }
    memset(vis,0,sizeof(vis));
    for(int i=l;i<=r;i++) que.push(node{i,a[i]});
    while(!que.empty()){
        while(!que.empty()&&(vis[que.top().d]||que.top().id<l)) que.pop();
        if(que.empty()) break;
        node x = que.top();que.pop();
        vis[x.d] = true,ans.push_back(x.d),l = x.id + 1;
        while(r+1<=n){
            if(vis[a[r]]||last[a[r]]!=r) {
                r++;
                if(!vis[a[r]]) que.push(node{r,a[r]});
            }
            else break;
        }
    }
    for(int i=0;i<ans.size();i++){
        printf("%d",ans[i]);
        if(i==ans.size()-1) printf("
");
        else printf(" ");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/EchoZQN/p/14505864.html