[NOIP2024] 编辑字符串

[NOIP2024] 编辑字符串

观察字符串的性质,很明显,对于一个全部可以参与互换的区间(简称区间),1和0出现的位置是无所谓的,因为我们可以通过交换任意改变他们的位置,所以我们对于一个区间只需要统计0和1出现的次数就行了,对于不能参与交换的位置,我们可以把他们处理成长度为1的区间,方便后面的计算

对与两个有相交的区间,考虑贪心做法,我们可以计算一下0和1中可以重合的数量,通过交换将尽量多的0/1在当前交区间内重合,因为区间内所有数都是可以交换随意改变位置的,所以对于一对可以重合的0/1,不论再当前的交区间中重合还是在之后的交区间中重合,对于答案的贡献都是1,而且不会影响后面的决策,所以我们的贪心是正确的

综上,我们只需要记录每一个区间,用双指针将所有交区间枚举出来,贪心统计答案即可

using namespace std;
#define ll long long
#define MAXN 100010 
inline ll read(){
	ll x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
struct node{
	ll l,r,sum1,sum0;
}a[MAXN*2],b[MAXN*2];
ll n,cnta,cntb,ans;
ll prea[MAXN],preb[MAXN];
string s;
ll T;
void work(){
	memset(prea,0,sizeof(prea));
	memset(preb,0,sizeof(preb));
	cnta=0,cntb=0,ans=0;
	cin>>n;
	cin>>s;
	for(int i=1;i<=n;i++){
		prea[i]=prea[i-1]+s[i-1]-'0';
	}
	cin>>s;
	for(int i=1;i<=n;i++){
		preb[i]=preb[i-1]+s[i-1]-'0';
	}
	ll l=1;
	cin>>s;
//	cout<<s<<endl;
	for(int i=1;i<=n;i++){
		if(s[i-1]=='0'){
			if(i>l){
				a[++cnta].l=l,a[cnta].r=i-1,a[cnta].sum1=prea[i-1]-prea[l-1];
				a[cnta].sum0=(i-l)-a[cnta].sum1;
			}
			a[++cnta].l=i,a[cnta].r=i,a[cnta].sum1=prea[i]-prea[i-1];
			a[cnta].sum0=1-a[cnta].sum1;
			l=i+1;
		}
	}
	if(n>=l){
		a[++cnta].l=l,a[cnta].r=n,a[cnta].sum1=prea[n]-prea[l-1];
		a[cnta].sum0=(n-l+1)-a[cnta].sum1;
	}
	l=1;
	cin>>s;
	for(int i=1;i<=n;i++){
		if(s[i-1]=='0'){
			if(i>l){
				b[++cntb].l=l,b[cntb].r=i-1,b[cntb].sum1=preb[i-1]-preb[l-1];
				b[cntb].sum0=(i-l)-b[cntb].sum1;
			}
			b[++cntb].l=i,b[cntb].r=i,b[cntb].sum1=preb[i]-preb[i-1];
			b[cntb].sum0=1-b[cntb].sum1;
			l=i+1;
		}
	}
	if(n>=l){
		b[++cntb].l=l,b[cntb].r=n,b[cntb].sum1=preb[n]-preb[l-1];
		b[cntb].sum0=(n-l+1)-b[cntb].sum1;
	}
	ll p=1;
	for(int i=1;i<=cnta;i++){
//		if(T==3)cout<<"\n------------------------------------------\n";
//		if(T==3)cout<<p<<" "<<cntb<<endl;
//		if(T==3)cout<<"a "<<i<<" l:"<<a[i].l<<" r:"<<a[i].r<<" "<<a[i].sum0<<" "<<a[i].sum1<<endl;
		while(p<=cntb){
//			if(T==3)cout<<"b "<<p<<" l:"<<b[p].l<<" r:"<<b[p].r<<" "<<b[p].sum0<<" "<<b[p].sum1<<endl;
			ll now1=min(a[i].sum1,b[p].sum1),now0=min(a[i].sum0,b[p].sum0),len=min(a[i].r,b[p].r)-max(a[i].l,b[p].l)+1;
			now1=min(now1,len);
			now0=min(now0,len);
			a[i].sum1-=now1,b[p].sum1-=now1,ans+=now1;
			a[i].sum0-=now0,b[p].sum0-=now0,ans+=now0;
//			cout<<now0<<" "<<now1<<" "<<a[i].sum0<<" "<<a[i].sum1<<endl;
			if(b[p].r<a[i].r)p++; 
			else{
				if(b[p].r==a[i].r)p++;
				break;
			}
		}
//		if(T==3)cout<<ans<<endl;
	}
	cout<<ans<<endl;
}
int main(){
//	freopen("edit2.in","r",stdin);
//	T=read();
	cin>>T;
	while(T--)work();
	return 0;
}
posted @ 2024-12-05 21:41  flyfreemrn  阅读(33)  评论(0)    收藏  举报