CF578E Walking!
Link
有解的充要条件是\(\text L\)和\(\text R\)的数量相差不超过\(1\)。
不难证明初始位置一定是可以选择的初始位置中最靠前的那个。
下文的合法位置指的是尚未被走到的字符与当前位置不同的位置。
然后我们有一个简单的贪心,是每次选择在当前位置后面的最靠前的合法位置走过去,如果不存在就用\(1\)的花费走回序列中的第一个合法位置。
这种贪心会有一个反例:
假如当前我们在一个为\(\text L\)的位置,这个位置后面的合法位置全都是\(\text R\),并且序列第一个合法位置也是\(\text R\),那么我们这一步应该用\(1\)的花费走到序列的第一个合法位置。
加上这个特判之后这个做法就没有问题了。
#include<set>
#include<cstdio>
#include<vector>
#include<cstring>
const int N=100007,inf=1e9;
int n;char str[N];std::vector<int>ans;std::set<int>s1,s2;
int getid(){return *s1.begin()<*s2.begin()? 1:2;}
void solve()
{
int cnt=0,now=2,pos=0,next=*s1.begin();
for(int i=1;i<=n;++i)
if(now==1)
{
if(next==inf||(getid()==2&&*s1.lower_bound(next)==inf&&*s2.begin()!=next)) ++cnt,next=*s2.begin();
pos=next,s2.erase(pos),next=*s1.lower_bound(pos),now=2,ans.push_back(pos);
}
else
{
if(next==inf||(getid()==1&&*s2.lower_bound(next)==inf&&*s1.begin()!=next)) ++cnt,next=*s1.begin();
pos=next,s1.erase(pos),next=*s2.lower_bound(pos),now=1,ans.push_back(pos);
}
printf("%d\n",cnt);
for(int x:ans) printf("%d ",x);
}
int main()
{
scanf("%s",str+1),n=strlen(str+1),s1.insert(inf),s2.insert(inf);
for(int i=1;i<=n;++i) (str[i]=='L'? s1:s2).insert(i);
if(s1.size()<s2.size()||(s1.size()==s2.size()&&*s1.begin()>*s2.begin())) s1.swap(s2);
solve();
}