C. awoo's Favorite Problem_思维+set

Problem - 1697C - Codeforces

题目大意

给字符串s和t。现有两种操作,操作1使“ab”变成“ba”,操作2使“bc”变成“cb”。问经过若干次操作后s有无可能变成t。

思路和代码

将两个字符串一位一位进行匹配。然后就有四种情况:

  • s_i==t_i 则匹配
  • s_i == 'a' and t_i == 'b' 则表明i位置的b需要从[i,n]中的某个位置(假设是j)移动而来。考虑要从j一路移到i,则表明[i,j]中没有字符c(不然就断掉了)。而可以贪心的想到,j位置就是[i,n]区间中字符b的第一次出现位置。
  • s_i == 'b' and t_i == 'c' 和上一种情况类似。
  • else

那么考虑如何编码:

做三个set,表示abc三种字符在[i,n]区间中的下标序列。然后两个字符串一位一位的对齐匹配,出现不匹配情况就尝试去将ti移动到si位置。总体是一个模拟的思路。

string solve2(){
	
	cin >> n ;
	string s , t ;
	cin >> s >> t ;
	s = " " + s ;
	t = " " + t ;
	
	set<ll> idx[3] ;
	rep(i , 1 , n)
	idx[s[i] - 'a'].insert(i) ;
	
	//[i,n]的abc三种字母的升序下标序列 
	
	rep(i , 1 , n){
//		cout << i << "=>" << s << "\n" ;
		if(s[i] == t[i]){//直接匹配 
			idx[s[i] - 'a'].erase(i) ;
			continue ;
		}
		if(s[i] == 'a' && t[i] == 'b'){
			//aaab 后面的b移到i位置 
			//baaa
			if(!idx[1].size()) return "NO\n" ;//没有b可以换到i位置 
			int posb = *idx[1].begin() ;
			int posc = *idx[2].begin() ;
			if(idx[2].size() && posc < posb) return "NO\n" ;
			idx[0].erase(i) ;
			idx[1].erase(posb) ;
			idx[0].insert(posb) ;
			swap(s[i] , s[posb]) ;
//			cout << i << " <- " << posb << "\n" ;
			continue ;
		}
		if(s[i] == 'b' && t[i] == 'c'){
			//bbbc
			//cbbb
			if(!idx[2].size()) return "NO\n" ; 
			int posc = *idx[2].begin() ;
			int posa = *idx[0].begin() ;
			if(idx[0].size() && posa < posc) return "NO\n" ;
			idx[1].erase(i) ;
			idx[2].erase(posc) ;
			idx[1].insert(posc) ;
			swap(s[i] , s[posc]) ;
			continue ;
		}
		return "NO\n" ;
	}
	return "YES\n" ;
}

接下来是堆的解法:

仔细思索一下整个解题步骤:

遇到不匹配的时候尝试从后面换一个匹配的字符过来。而这个交换就是在字符的下标序列里面插入一个新的点。而每次交换的时候,换过来的字符肯定是所有同种字符里的第一个。就是每次取头,再插入。所以优先队列完美胜任。要注意在交换的时候对堆的维护,细节写在代码里了。

string solve3(){
	string s , t ;
	cin >> n >> s >> t ;
	
	s = " " + s ;
	t = " " + t ;
	
	priority_queue<ll , vct<ll> , greater<ll> > idx[3] ;
	
	rep(i , 1 , n) idx[s[i] - 'a'].push(i) ;
	
	rep(i , 1 , n){
//		cout << i << " " << s << "\n" ;
		if(s[i] == t[i]){
//			cout << idx[s[i] - 'a'].top() << "\n" ;
			idx[s[i] - 'a'].pop() ;
			continue ;
		}
		if(s[i] == 'a' && t[i] == 'b'){
			if(!idx[1].size()) return "NO\n" ;//后面没有b可以交换到第i位
			int posb = idx[1].top() ;
			if(idx[2].size()){
				int posc = idx[2].top() ;
				if(posc < posb) return "NO\n" ;//中间被c截断了,b移不到i位置
			}
//			cout << idx[s[i] - 'a'].top() << "\n" ;
			idx[s[i] - 'a'].pop() ;
			swap(s[i] , s[posb]) ;//交换 
			idx[1].pop() ;
			idx[0].push(posb) ; 
			continue ;
		}
		if(s[i] == 'b' && t[i] == 'c'){
			if(!idx[2].size()) return "NO\n" ;//后面没有c可以交换到第i位
			int posc = idx[2].top() ;
			if(idx[0].size()){
				int posa = idx[0].top() ;
				if(posa < posc) return "NO\n" ;//中间被a截断了,c移不到i位置
			}
//			cout << idx[s[i] - 'a'].top() << "\n" ;
			idx[s[i] - 'a'].pop() ;
			swap(s[i] , s[posc]) ;//交换 
			idx[2].pop() ;
			idx[1].push(posc) ; 
			continue ;
		}
		return "NO\n" ;
	}
	return "YES\n" ;
}

小结

考试周军训周终于结束了,可以好好开始准备比赛,先复建两天,捋一捋知识点。做一做思维题,我尤其需要锻炼思考的能力(我只会打板子)

其实这题并不难,而且set和堆的解法其实类似。写这么多可能显的有点累赘,但是我的目的是做到100%ok,整个题目要思考清楚。

有的时候潜意识里会在做题的时候偷懒,蒙结论,猜对了就直接过。这样确实爽但是没有任何效果,是在纯纯浪费时间。不能欺骗自己啊,加油。

posted @   tyrii  阅读(144)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示