【Codeforces 578E】Walking!
贪心。
题目大意:
给定一个 $01$ 序列 $a$,要求找到一个排列 $p$ 使得 $\forall i\in[1,n-1]$,满足 $a_{p_i}\neq a_{p_{i+1}}$。
要求 $p_i>p_{i+1}$ 的 $i$ 的个数尽可能少。
输出最少个数,并给出构造方案。
题解:
贪心。
每次找到一个能够匹配的进行匹配,找不到就自己新开一个。
最后将若干段进行合并,分类讨论即可。
这里匹配的时候要注意,对于一个位置,要找到之前的最靠前的匹配,这样才能保证能够正确匹配。否则类似 LRRL
的就会导致最后无法合并。
时间复杂度 $O(n)$。
Code:
#include<cstdio>
#include<set>
#include<vector>
#include<deque>
#include<cstring>
using namespace std;
const int N=2e5+5;
set<int>st[2];
int n,cnt;
char s[N];
vector<int>res[N],id[4];
deque<int>L,R;
inline void out(vector<int>&v){for(int i:v)printf("%d ",i);}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;++i)
if(s[i]=='L'){
if(R.empty()){
res[++cnt].push_back(i);
L.push_back(cnt);
}else{
int x=R.front();
res[x].push_back(i);
L.push_back(x);
R.pop_front();
}
}else{
if(L.empty()){
res[++cnt].push_back(i);
R.push_back(cnt);
}else{
int x=L.front();
res[x].push_back(i);
R.push_back(x);
L.pop_front();
}
}
printf("%d\n",cnt-1);
for(int i=1;i<=cnt;++i){
const int zt=(s[res[i].front()]=='R')<<1|(s[res[i].back()]=='R');
id[zt].push_back(i);
}
if(id[3].size()>id[0].size()){
for(int i:id[2])out(res[i]);
while(id[3].size()&&id[0].size()){
int x=id[3].back();id[3].pop_back();
out(res[x]);
x=id[0].back();id[0].pop_back();
out(res[x]);
}
while(id[3].size()){
int x=id[3].back();id[3].pop_back();
out(res[x]);
}
for(int i:id[1])out(res[i]);
}else
if(id[3].size()<id[0].size()){
for(int i:id[1])out(res[i]);
while(id[3].size()&&id[0].size()){
int x=id[0].back();id[0].pop_back();
out(res[x]);
x=id[3].back();id[3].pop_back();
out(res[x]);
}
while(id[0].size()){
int x=id[0].back();id[0].pop_back();
out(res[x]);
}
for(int i:id[2])out(res[i]);
}else{
for(int i:id[2])out(res[i]);
while(id[3].size()>1&&id[0].size()>1){
int x=id[3].back();id[3].pop_back();
out(res[x]);
x=id[0].back();id[0].pop_back();
out(res[x]);
}
while(id[3].size()){
int x=id[3].back();id[3].pop_back();
out(res[x]);
}
for(int i:id[1])out(res[i]);
while(id[0].size()){
int x=id[0].back();id[0].pop_back();
out(res[x]);
}
}
return 0;
}