题解 CF578E/nflsoj621 Walking! 奇怪的脚印

注:本题最初来源是CF578E Walking,后被选入IOI2020国家队作业,之后又出现在六校联考 #33这场模拟赛中。

首先,将整个串划分为,尽可能少的、\(\text{L},\text{R}\)交替的子序列(不一定连续),再考虑将这些子序列拼起来。设划分出了\(k\)个子序列,则答案的下界显然是\(k-1\)。确定了一种划分方法后,我们要做的,是构造一种拼接这些子序列的方法,使答案取到这个下界。

划分,可以贪心解决。从前向后依次考虑\(S\)的每个位置。维护前面已经划分出的所有子序列。如果有末尾字母和\(S\)当前位置上字母不同的子序列,就把当前位置加入到这个子序列中,否则就令当前位置单独作为一个子序列。这样就愉快地划分好了(正确性请感性理解)。

接下来要构造拼接方案。我们把划分出的这些子序列,按照首、尾字母,分为:\(\text{LL}\), \(\text{RR}\), \(\text{LR}\), \(\text{RL}\)四类。


因为题目保证了\(\text{L},\text{R}\)的总数相差不超过\(1\),所以\(\text{LL}\), \(\text{RR}\)两类子序列的数量相差不超过\(1\)。考虑先将这两类子序列拼接起来:

  • 如果\(\text{LL}\), \(\text{RR}\)数量相等,则可以得到一个大的,形如:\(\text{LR}\)的“子序列”。注意,这里打引号的“子序列”,意思是它实际上并不真的是原序列的一个子序列,因为在拼接时,会有“跳回去”(也就是“倒着走”)的情况。但这个“子序列”,代表的含义是连续的一段脚印,所以在构造方案时,它和真正的子序列没有区别。在下面的表述中,我们会用引号和斜体标注这种等价的“子序列”,如果未被标注,则表示通常意义上的子序列。
  • 如果\(\text{LL}\)\(\text{RR}\)多,则可以得到一个形如\(\text{LL}\)的“子序列”。
  • 如果\(\text{RR}\)\(\text{LL}\)多,则可以得到一个形如\(\text{RR}\)的“子序列”。

经过这一番拼接,我们手上,\(\text{LL}\), \(\text{RR}\)两种“子序列”,最多只剩一个。


再考虑拼接\(\text{LR}\), \(\text{RL}\)这两类“子序列”。我们首先可以把所有\(\text{LR}\)拼成一个大的\(\text{LR}\),也可以把所有\(\text{RL}\)拼成一个大的\(\text{RL}\)。现在我们手上最多只剩一个\(\text{LR}\)和一个\(\text{RL}\)。怎样把它们拼在一起呢?比较棘手。这也是本题的难点。

考虑\(\text{LR}\)\(\text{RL}\)的最后一个位置(是脚印序列的最后一个脚印,但并不一定是“子序列”中坐标最大的位置,因为“子序列”可能存在“跳回去”的情况),分别记为\(p\), \(q\)。不妨假设\(p<q\)。那么,我们可以把\(q\)这个位置上的\(\text{L}\),接到\(\text{LR}\)序列的末尾,再把\(\text{RL}\)序列,除了\(q\)以外的其它部分,(从前往后)依次接在后面。这样,我们就用\(1\)次“跳回去”的操作,成功合并了\(\text{LR}\)\(\text{RL}\)两个“子序列”。

现在,我们手上,\(\text{LR}\), \(\text{RL}\)两种“子序列”,最多只剩一个。


综上,在最后,我们手上的子序列,有如下几种可能:

  • 只剩一个“子序列”了。那么它的长度必为\(n\),直接把这个“子序列”输出即可。
  • \(\text{LL}\), \(\text{RR}\)两种中的一个,和\(\text{LR}\), \(\text{RL}\)两种中的一个。分四类情况讨论一下,在满足\(\text{L},\text{R}\)交替的前提下,将它们拼接即可。

时间复杂度,\(O(|S|)\)

参考代码:

//problem:nflsoj621
#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define mk make_pair
#define lob lower_bound
#define upb upper_bound
#define fi first
#define se second
#define SZ(x) ((int)(x).size())

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;

const int MAXN=1e5;
int n,cnt;
char s[MAXN+5];
vector<int>vL,vR,v[MAXN+10];
vector<int>LL,RR,LR,RL;

int main() {
	cin>>(s+1);
	n=strlen(s+1);
	for(int i=1;i<=n;++i){
		if(s[i]=='L'){
			if(!SZ(vR)){
				++cnt;
				vL.pb(cnt);
				v[cnt].pb(i);
			}
			else{
				vL.pb(vR.back());
				v[vR.back()].pb(i);
				vR.pop_back();
			}
		}
		else{
			if(!SZ(vL)){
				++cnt;
				vR.pb(cnt);
				v[cnt].pb(i);
			}
			else{
				vR.pb(vL.back());
				v[vL.back()].pb(i);
				vL.pop_back();
			}
		}
	}
	cout<<cnt-1<<endl;
	for(int i=1;i<=cnt;++i){
		int st=v[i][0],ed=v[i].back();
		if(s[st]=='L' && s[ed]=='L')LL.pb(i);
		if(s[st]=='R' && s[ed]=='R')RR.pb(i);
		if(s[st]=='L' && s[ed]=='R')LR.pb(i);
		if(s[st]=='R' && s[ed]=='L')RL.pb(i);
	}
	if(SZ(LL) && SZ(RR)){
		if(SZ(LL)==SZ(RR)){
			++cnt;
			LR.pb(cnt);
			for(int i=0;i<SZ(LL);++i){
				for(int j=0;j<SZ(v[LL[i]]);++j)v[cnt].pb(v[LL[i]][j]);
				for(int j=0;j<SZ(v[RR[i]]);++j)v[cnt].pb(v[RR[i]][j]);
			}
			vector<int>().swap(LL);
			vector<int>().swap(RR);
		}
		else if(SZ(LL)>SZ(RR)){
			assert(SZ(RR)==SZ(LL)-1);
			++cnt;
			for(int i=0;i<SZ(RR);++i){
				for(int j=0;j<SZ(v[LL[i]]);++j)v[cnt].pb(v[LL[i]][j]);
				for(int j=0;j<SZ(v[RR[i]]);++j)v[cnt].pb(v[RR[i]][j]);
			}
			int i=SZ(RR);
			for(int j=0;j<SZ(v[LL[i]]);++j)v[cnt].pb(v[LL[i]][j]);
			vector<int>(1,cnt).swap(LL);
			vector<int>().swap(RR);
		}
		else{
			assert(SZ(LL)==SZ(RR)-1);
			++cnt;
			for(int i=0;i<SZ(LL);++i){
				for(int j=0;j<SZ(v[RR[i]]);++j)v[cnt].pb(v[RR[i]][j]);
				for(int j=0;j<SZ(v[LL[i]]);++j)v[cnt].pb(v[LL[i]][j]);
			}
			int i=SZ(LL);
			for(int j=0;j<SZ(v[RR[i]]);++j)v[cnt].pb(v[RR[i]][j]);
			vector<int>().swap(LL);
			vector<int>(1,cnt).swap(RR);
		}
	}
	assert(SZ(LL)<=1);assert(SZ(RR)<=1);assert(!(SZ(LL)==1 && SZ(RR)==1));
	if(SZ(LR)>1){
		++cnt;
		for(int i=0;i<SZ(LR);++i){
			for(int j=0;j<SZ(v[LR[i]]);++j)v[cnt].pb(v[LR[i]][j]);
		}
		vector<int>(1,cnt).swap(LR);
	}
	if(SZ(RL)>1){
		++cnt;
		for(int i=0;i<SZ(RL);++i){
			for(int j=0;j<SZ(v[RL[i]]);++j)v[cnt].pb(v[RL[i]][j]);
		}
		vector<int>(1,cnt).swap(RL);
	}
	assert(SZ(LR)<=1);assert(SZ(RL)<=1);
	if(SZ(LR) && SZ(RL)){
		if(v[LR[0]].back() > v[RL[0]].back()){
			v[RL[0]].pb(v[LR[0]].back());
			for(int i=0;i<=SZ(v[LR[0]])-2;++i)
				v[RL[0]].pb(v[LR[0]][i]);
			vector<int>().swap(LR);
		}
		else{
			v[LR[0]].pb(v[RL[0]].back());
			for(int i=0;i<=SZ(v[RL[0]])-2;++i)
				v[LR[0]].pb(v[RL[0]][i]);
			vector<int>().swap(RL);
		}
	}
	#define printv(v) do{for(int i=0;i<SZ((v));++i)cout<<(v)[i]<<" ";}while(0)
	if(!SZ(LL) && !SZ(RR)){
		if(SZ(LR))printv(v[LR[0]]);
		if(SZ(RL))printv(v[RL[0]]);
	}
	else if(!SZ(LR) && !SZ(RL)){
		if(SZ(LL))printv(v[LL[0]]);
		if(SZ(RR))printv(v[RR[0]]);
	}
	else if(SZ(LL) && SZ(LR)){
		printv(v[LR[0]]);printv(v[LL[0]]);
	}
	else if(SZ(LL) && SZ(RL)){
		printv(v[LL[0]]);printv(v[RL[0]]);
	}
	else if(SZ(RR) && SZ(LR)){
		printv(v[RR[0]]);printv(v[LR[0]]);
	}
	else if(SZ(RR) && SZ(RL)){
		printv(v[RL[0]]);printv(v[RR[0]]);
	}
	else assert(0);
	cout<<endl;
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/dysyn1314/p/12960424.html