B. Perfect Flush
題目大意
給你N個數,每個數不超過K,並且保障從 1 到 K 的每個數字至少出現一次,讓你從這 N 數字中選出來K個數保障每個數都出現一次並且這個子序列的字典序最小;
解題思路
這個可以用單調棧來解決,預先統計每個數字最後一次出現的位置,然後我們想棧中添加元素,如果這個元素添加過了就不用管,如果沒用就向裏面加,加的時候判斷下這個數字是不是當前棧中最上面的元素小如果小並且棧頂元素在後面還有那就把棧頂元素移出去,知道上面條件不滿足的時候結束,添加當前元素;
代碼
#include<bits/stdc++.h>
using namespace std;
const int M=200200;
int last[M],a[M],ans[M];//last 用來記錄最後一次出現的位置
bool f[M];
int main()
{
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
last[a[i]]=i;
}
int top=0;
for(int i=1;i<=n;i++)
{
if(!f[a[i]]){//如果沒在棧中就進行入棧前的檢測
//如果棧頂元素大於當前元素 且 棧頂元素在後面還會出現就先移除
//棧頂元素讓這個元素儘可能的向前放置
while (top&&ans[top]>a[i]&&i<last[ans[top]])
{
f[ans[top]]=0;//取消標記
top--;
}
f[a[i]]=1;
top++;//將這個元素放入棧中
ans[top]=a[i];
}
}
cout<<ans[1];
for(int i=2;i<=top;i++) cout<<" "<<ans[i];
cout<<"\n";
return 0;
}