[NOIP2024] 编辑字符串 题解

[NOIP2024] 编辑字符串 题解


知识点

贪心。


题意简述

给定两个 01 序列,规定每个序列某些位置可以进行左右互换操作。

要求求出操作后两序列一一对应相同的值最多有多少。


题目分析

其实可以很简单地想到一个贪心:将能对上的就对上。

然后发现这是对的,因为能互换的位置是固定的,这就导致先把最多的取出一定不劣。

那么知道了这个贪心之后就变成了想一个法子来模拟即可。


代码

//#define Plus_Cat "edit"
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e5+10);

namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
	struct Icat {

		char getc() {
			return getchar();
		}

		template<class T>void operator ()(T &x) {
			static bool sign(0);
			static char ch(0);
			sign=0,x=0;
			while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
			do x=(x<<1)+(x<<3)+(ch^48);
			while(ch=getc(),isD(ch));
			if(sign)x=-x;
		}

		template<class T,class...Types>void operator ()(T &x,Types&...args) {
			return (*this)(x),(*this)(args...);
		}

	} I;
	struct Ocat {

		void putc(char c) {
			putchar(c);
		}

		template<class T>void operator ()(T x,const char lst='\n') {
			static int top(0);
			static char st[100];
			if(x<0)x=-x,putc('-');
			do st[++top]=(x%10)^48,x/=10;
			while(x);
			while(top)putc(st[top--]);
			putc(lst);
		}

		template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
			return (*this)(x,lst),(*this)(args...);
		}

	} O;
	struct Ecat {

		template<class T>void operator ()(const char *fmt,const T x) {
			cerr<<fmt<<':'<<x<<'.'<<endl;
		}

		template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
			while(*fmt^',')cerr<<*fmt++;
			return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
		}

	} E;

} using namespace IOEcat;

char S0[N],S1[N],T0[N],T1[N];
int Cas,n,tot0,tot1,ans;
int id0[N],id1[N];
int cnt0[N][2],cnt1[N][2];

int Cmain() {
	/*Input*/
	I(n),scanf("%s%s%s%s",S0+1,S1+1,T0+1,T1+1);
	/*Init*/
	tot0=0,tot1=0,ans=0;
	RCL(id0,0,id0,1),RCL(id1,0,id1,1),RCL(cnt0,0,cnt0,1),RCL(cnt1,0,cnt1,1);
	/*Solve*/
	FOR(i,1,n)if(T0[i]=='1') {
		++tot0,cnt0[tot0][0]=cnt0[tot0][1]=0;
		int j(i);
		while(j<=n&&T0[j]=='1')++cnt0[id0[j]=tot0][S0[j]^'0'],++j;
		i=j-1;
	}
	FOR(i,1,n)if(T1[i]=='1') {
		++tot1,cnt1[tot1][0]=cnt1[tot1][1]=0;
		int j(i);
		while(j<=n&&T1[j]=='1')++cnt1[id1[j]=tot1][S1[j]^'0'],++j;
		i=j-1;
	}
	FOR(i,1,n) {
		if(id0[i]) {
			if(id1[i]) {
				if(cnt0[id0[i]][0]>0&&cnt1[id1[i]][0]>0)--cnt0[id0[i]][0],--cnt1[id1[i]][0],++ans;
				else if(cnt0[id0[i]][1]>0&&cnt1[id1[i]][1]>0)--cnt0[id0[i]][1],--cnt1[id1[i]][1],++ans;
				else if(cnt0[id0[i]][0]>0&&cnt1[id1[i]][1]>0)--cnt0[id0[i]][0],--cnt1[id1[i]][1];
				else if(cnt0[id0[i]][1]>0&&cnt1[id1[i]][0]>0)--cnt0[id0[i]][1],--cnt1[id1[i]][0];
			} else {
				bool val(S1[i]^'0');
				if(cnt0[id0[i]][val]>0)--cnt0[id0[i]][val],++ans;
				else if(cnt0[id0[i]][val^1]>0)--cnt0[id0[i]][val^1];
			}
		} else {
			if(id1[i]) {
				bool val(S0[i]^'0');
				if(cnt1[id1[i]][val]>0)--cnt1[id1[i]][val],++ans;
				else if(cnt1[id1[i]][val^1]>0)--cnt1[id1[i]][val^1];
			} else ans+=(S0[i]==S1[i]);
		}
	}
	/*Output*/
	O(ans,'\n');
	return 0;
}

int main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	for(I(Cas); Cas; --Cas)Cmain();
	return 0;
}

反思

做题目时思路有些复杂,状态不是很好,导致引起了代码时的混乱,调试花了一些时间,并且重构了一次代码。

posted @ 2025-11-17 20:42  Add_Catalyst  阅读(5)  评论(0)    收藏  举报