[NOIP2024] 编辑字符串

比较简单的贪心

首先按照\(t_1,t_2\)中连续的\(1\)将其分成若干段。以样例为例,\(t_1=111010\),那么第一段是\(s_1[1\sim3]\),第二段是\(s_1[5]\)\(t_2=101101\),那么第三段是\(s_2[1]\),第四段是\(s_2[3\sim4]\),第五段是\(s_2[6]\).同时统计每一段中,\(s_1(s_2)\)\(1\)\(0\)的数量

然后可以知道,如果对一个位置\(i\),有\(t_1[i]=t_2[i]=0\),那么答案是可以直接统计的(若\(s_1[i]=s_2[i]\)则答案加一,否则答案不变);若\(t_1[i]+t_2[i]=1\)则我们尽量匹配(比如\(t_1=1,t_2=0,s_2[i]=0\),那么考虑\(i\)所在的段剩下的\(0\)的个数,如果还有剩下的\(0\),那么将这个\(0\)\(s_2[i]\)进行匹配,并将\(i\)所属的这个段的\(0\)的个数减一);在优先考虑完所有的\(t_1[i]+t_2[i]=1\)的位置后,再考虑\(t_1[i]+t_2[i]=2\)的位置\(i\),随意将剩下的\(0/1\)进行匹配即可

上述做法的正确性可以用决策包容性证明。简单来说,就是任意一个位置对答案的贡献只有\(1\),上面的做法,我们在分配任意一个\(0/1\)的时候,都保证了这个\(0/1\)对答案的贡献增加了一。如果我们不把这个\(0/1\)分配到这个位置,分配到其他位置的贡献也是一,等价于就放在这个位置

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
int n;
char s1[N],s2[N],t1[N],t2[N];
int mark[N],belong[2][N],sum[N][2],cnt;
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		cnt=0;//cnt记录段的数量 
		for(int i=1;i<=n;i++) 
		{
			for(int j=0;j<=1;j++) belong[j][i]=sum[i][j]=0;
			//belong[0/1][i]表示s1/s2的位置i所属的段的标号
			//sum[i][0/1]表示编号为i的段的0/1的个数 
			mark[i]=0;//mark[i]表示位置i的类别 
		}
		scanf("%s%s",s1,s2);
		scanf("%s%s",t1,t2);
		for(int i=1;i<=n;i++)
		if(t1[i-1]=='1') mark[i]++;
		for(int i=1;i<=n;i++)
		if(t2[i-1]=='1') mark[i]+=2;
		for(int i=1;i<=n;i++)
		if(t1[i-1]=='1')
		{
			cnt++;
			int j=i;
			while(j<=n&&t1[j-1]=='1')
			{
				belong[0][j]=cnt;
				sum[cnt][s1[j-1]-'0']++;
				j++;
			}
			i=j-1;
		}
		for(int i=1;i<=n;i++)
		if(t2[i-1]=='1')
		{
			cnt++;
			int j=i;
			while(j<=n&&t2[j-1]=='1')
			{
				belong[1][j]=cnt;
				sum[cnt][s2[j-1]-'0']++;
				j++;
			}
			i=j-1;
		}
		int ans=0;
		for(int i=1;i<=n;i++)
		if(!mark[i]&&s1[i-1]==s2[i-1]) ans++;
		for(int i=1;i<=n;i++)
		if(mark[i]==1&&sum[belong[0][i]][s2[i-1]-'0'])
		{
			sum[belong[0][i]][s2[i-1]-'0']--;
			ans++;
		}
		else if(mark[i]==2&&sum[belong[1][i]][s1[i-1]-'0'])
		{
			sum[belong[1][i]][s1[i-1]-'0']--;
			ans++;
		}
		for(int i=1;i<=n;i++)
		if(mark[i]==3) 
		{
		    if(sum[belong[0][i]][0]&&sum[belong[1][i]][0])
		    {
		        ans++;
		        sum[belong[0][i]][0]--,sum[belong[1][i]][0]--;
		    }
		    if(sum[belong[0][i]][1]&&sum[belong[1][i]][1])
		    {
		        ans++;
		        sum[belong[0][i]][1]--,sum[belong[1][i]][1]--;
		    }
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2025-01-18 22:40  最爱丁珰  阅读(141)  评论(0)    收藏  举报