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();
}
posted @ 2020-05-16 15:54  Shiina_Mashiro  阅读(202)  评论(0编辑  收藏  举报