[NOIP2024] 编辑字符串

题目传送门

T1 蓝切了,T2 绿只得了 20 分......

题意分析

给定字符串 \(s_1,s_2\) 和标记数组 \(t_1,t_2\)\(t_i[j]\) 表示 \(s_i\) 的第 \(j\) 位是否可以参与交换。

同一字符串内任意两个可以参与交换的相邻的字符可以交换,让你求出最多有多少位是相同的。

我们其实可以使用一个很简单的贪心来求解。

首先,对于第 \(i\) 位,如果能够通过交换使得 \(s_1[i]=s_2[i]\),那么交换一定是不劣的(即最优)

原因也很简单,具体而言就是对于第 \(i\) 号位,你换了,最多让后面少换一个,但是你不换后面最多也只能换一个。

\(cnt_i[j]\) 表示 \(s_i\) 当前能够进行交换的 \(j\) 的数量,\(j\in\{0,1\}\),令 \(ans\) 为最终答案,初始值为 \(0\)

那么我们就可以进行一个分讨:

  • \(t_1[i]=t_2[i]=0\)\(s_1,s_2\) 的第 \(i\) 号位都不能换,若 \(s_1[i]=s_2[i]\) 就计数,否则跳过。
  • \(t_1[i]=0,t_2[i]=1\)\(s_1[i]\) 不能交换,我们考虑将 \(s_2[i]\) 换成 \(s_1[i]\);那么我们看看 \(cnt_2[s_1[i]]\) 是否大于 \(0\),是就代表 \(s_2[i]\) 能够交换为 \(s_1[i]\),令 \(cnt_2[s_1[i]]\leftarrow cnt_2[s_1[i]]-1\) 并计数即可;否则跳过。
  • \(t_1[i]=1,t_2[i]=0\)\(s_2[i]\) 不能交换;同理,\(cnt_1[s_2[i]]>0\) 时令其自减并计数,否则跳过。
  • \(t_1[i]=t_2[i]=1\):随便换;如果都能换成 \(0\) 就都换成 \(0\),否则如果能都换成 \(1\) 就换成 \(1\);方法同理可得。

那么如何求 \(cnt_i\) 呢?

其实也很简单,可以视作被 \(t_i[j]=0\)\(j\) 分为了一段一段,在 \(t_i[j]=0\) 时找到最小的 \(j'\) 满足 \(t_i[j']=0\) 然后统计区间 \([j+1,j'-1]\) 即可。

总时间复杂度:\(\mathcal O(n)\)

AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
const int N=1e5;
int n;
char s1[N+1],s2[N+1],t1[N+1],t2[N+1];
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d%s%s%s%s",&n,s1,s2,t1,t2);
		int cnt1[2]={},cnt2[2]={};
		int ans=0;
		for(int j=0;t1[j]=='1';j++)cnt1[s1[j]-'0']++;
		for(int j=0;t2[j]=='1';j++)cnt2[s2[j]-'0']++;
		for(int i=0;i<n;i++){
			if(t1[i]=='0'){
				if(t2[i]=='0'){
					if(s1[i]==s2[i])ans++;
				}else{
					if(cnt2[s1[i]-'0']>0)ans++,cnt2[s1[i]-'0']--;
				}
			}else{
				if(t2[i]=='0'){
					if(cnt1[s2[i]-'0']>0)ans++,cnt1[s2[i]-'0']--;
				}else{
					if(cnt1[0]&&cnt2[0])ans++,cnt1[0]--,cnt2[0]--;
					else if(cnt1[1]&&cnt2[1])ans++,cnt1[1]--,cnt2[1]--;
				}
			}
			if(t1[i]=='0'){
				cnt1[0]=cnt1[1]=0;
				for(int j=i+1;t1[j]=='1';j++)cnt1[s1[j]-'0']++;
			}
			if(t2[i]=='0'){
				cnt2[0]=cnt2[1]=0;
				for(int j=i+1;t2[j]=='1';j++)cnt2[s2[j]-'0']++;
			}
		}printf("%d\n",ans);
	}
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
posted @ 2025-07-20 19:51  TH911  阅读(11)  评论(0)    收藏  举报