题意
略。
题解
好毒瘤啊,我最多就口胡第一问的样子吧。
第一问很显然(跟凤凰县探险队员一样显然),就是每次贪心选长度最大的满足条件的子序列,选不到就折返回来。所以折返的次数很明显就是选出子序列的个数 (-1)。
考虑第二问,很明显不能暴力拼接子序列,这样很容易被 hack。具体方法剩下的题解有讲。
注意到找到的子序列可以按照开头和结尾分成 (4) 类:LL
,LR
,RL
和 RR
。
首先有一个性质:可以将所有的 LR
拼在一起得到一个更长的 LR
,RL
同理。
接下来 LL
和 RR
有一个特殊的作用,就是将一段 LR
和一段 RL
拼起来,类似于 L...RL...LR...L
和 R...LR...RL...R
。(这里两个字母中间三个点表示一段子序列)
但是有些时候,没有 LL
和 RR
,但是有 LR
和 RL
,这两段是无法拼起来的。难道我们就这样失败了吗?没有的事!
我们可以通过已经有的 LR
和 RL
自己造一个 LL
和 RR
出来。具体地话就是考虑 LR
与 RL
中最后一个位置的关系。然后最后一个位置小的那个序列把最后一个位置给大的那个,然后 LR
就变成了 LL
,而 RL
就变成了 RR
。
然后这题就做完了。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51;
ll n,tot,x,y,swp;
vector<ll>v[MAXN],vg[2],g[2][2];
char ch[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
int main()
{
scanf("%s",ch+1),n=strlen(ch+1);
for(register int i=1;i<=n;i++)
{
x=ch[i]=='R',vg[x^1].empty()?vg[x^1].push_back(++tot):(void)1;
y=vg[x^1].back(),v[y].push_back(i);
vg[x^1].pop_back(),vg[x].push_back(y);
}
printf("%d
",tot-1);
for(register int i=1;i<=tot;i++)
{
g[v[i].size()&1][ch[v[i].back()]=='R'].push_back(i);
}
if(!g[0][0].empty()&&!g[0][1].empty()&&g[1][0].empty()&&g[1][1].empty())
{
x=g[0][0].back(),y=g[0][1].back();
v[x].back()<v[y].back()?1:(swap(x,y),swp=1);
v[x].push_back(v[y].back()),v[y].pop_back();
g[0][0].pop_back(),g[0][1].pop_back(),swp?swap(x,y):(void)1;
g[1][0].push_back(y),g[1][1].push_back(x);
}
if(g[1][0].size()!=g[1][1].size())
{
x=g[1][1].size()>g[1][0].size();
}
else
{
x=g[0][0].size()>g[0][1].size();
}
while(!g[0][x^1].empty())
{
for(register int i:v[g[0][x^1].back()])
{
printf("%d ",i);
}
g[0][x^1].pop_back();
}
while(!g[1][x].empty())
{
for(register int i:v[g[1][x].back()])
{
printf("%d ",i);
}
g[1][x].pop_back();
while(!g[0][x].empty())
{
for(register int i:v[g[0][x].back()])
{
printf("%d ",i);
}
g[0][x].pop_back();
}
x^=1;
}
}