Codeforces Round 967 (Div. 2)-D
这些天在留校集训……我之前空余时间在看模电,最近在玩黑猴……九月开学了估计也不能闲下来……但这个博客我还是会抽空更新的╰(°▽°)╯
Problem - D - Codeforces
虽然代码写得特别丑陋,但好歹是我完全想的思路——自己还de了一天bug(゜ー゜)
从上午十点开始看题到下午1点过,一直在想思路和可行的方法,期间也考虑过主席树(发现不会),最后还是用回了
朴实无华万能的双指针……然后就是debug到了今天早上才过……
分析
题中要求从给出的序列中选出一个长度最长同时在奇数位为负的情况下字典序最小的无重复元素的子序列
首先,要长度最长又没有重复元素,合法子序列一定是原序列中所有出现过的数的排列,再考虑字典序最小,容易想到要奇数位字典序尽量大、偶数位字典序尽量小,这里为什么要说"尽量"?因为要满足子序列不能乱序且选到原序列中的所有元素,为了方便思考,我们把问题简化一下,考虑如何选到长度最长的字典序最大的无重复子序列
对于 $ 2\ 1\ 3 $ 我们发现合法子序列只能是 $ 2\ 1\ 3 $ ,再考虑有一个重复元素的情况,对于 $ 3\ 2\ 1\ 3 $ 这时的合法子序列是 $ 3\ 2\ 1 $ ,有两个重复元素的情况—— $ 2\ 3\ 2\ 1\ 3 $ ,合法子序列还是 $ 3\ 2\ 1 $ ,考虑每一个元素,我们选了的话就只能选这个元素以后的元素,设这个元素的位置pos,也就是说[pos,n]内要包含所有我们还未选的元素,因此这个显然唯一元素是必选的
代码
void solve(){
int n;cin>>n;
vector<int>a(n+1),ans;
map<int,int>mp;
rep(i,1,n) cin>>a[i],mp[a[i]]++;
priority_queue<pair<int,int>>q,_q;
int sz=mp.size();
auto erase=[&](int idx)->void{
while(q.size()&&(-q.top().second<idx||mp[q.top().first]==0)){
q.pop();
}
while(_q.size()&&(-_q.top().second<idx||mp[-_q.top().first]==0)){
_q.pop();
}
};
int pos=1,i=1,j=1;
while(i<=n&&j<=n){
while(j<=n){
if(mp[a[j]]==0){
j++;
}
else if(mp[a[j]]==1){
q.push({a[j],-j});
_q.push({-a[j],-j});
break;
}
else{
mp[a[j]]--;
q.push({a[j],-j});
_q.push({-a[j],-j});
j++;
}
}
if(j>n) break;
int st1=-q.top().second,st2=-_q.top().second;
int mx=a[st1],mi=a[st2];
if(pos&1){
i=st1+1;
mp[mx]=0;
}
else{
i=st2+1;
mp[mi]=0;
}
pos++;
erase(i);
ans.push_back(a[i-1]);
}
cout<<ans.size()<<"\n";
for(auto i:ans) cout<<i<<" ";
cout<<"\n";
}
标签:967,int,元素,Codeforces,pos,序列,Div,字典
From: https://www.cnblogs.com/mono-4/p/18373798