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


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

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

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

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


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

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

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


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

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

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


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

    • 只剩一个“子序列”了。那么它的长度必为(n),直接把这个“子序列”输出即可。
    • ( ext{LL}), ( ext{RR})两种中的一个,和( ext{LR}), ( ext{RL})两种中的一个。分四类情况讨论一下,在满足( ext{L}, ext{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;
    }
    
  • 相关阅读:
    数据挖掘笔记(2018-03-22发布于知乎)
    使用Graphlab参加Kaggle比赛(2017-08-20 发布于知乎)
    大数据笔记
    2018网易游戏数据挖掘实习生笔试面经
    数据库课程设计之图书借阅管理系统
    居中
    lucene
    eclipse中使用git
    yii
    工作总结
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/12960424.html
Copyright © 2020-2023  润新知