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;
}