CF1978E 题解

特殊情况

首先考虑当 l=1,r=nl=1,r=n 时怎么做。

一个最优的操作方案是:

先对 aa 进行操作 11,使 bb 拥有尽可能多的 1,再对 bb 进行操作 22,这样 aa 中的 1 数量就是最多的了。

一般情况

fi,jf_{i,j} 表示进行上述操作方案后 aa 的区间 [i,j][i,j] 中的 1 的个数,gi,jg_{i,j} 表示区间 [i,j][i,j] 的答案。

显然 f1,n=g1,nf_{1,n}=g_{1,n}

而当 rl+1<nr-l+1\lt n 时(既有 l1l\not=1rnr\not=n),gl,rg_{l,r} 不一定等于 fl,rf_{l,r}


ci,0c_{i,0} 表示 aa 中的第 ii 位是否是由 00 变为 11 的,ci,1c_{i,1} 表示 bb 中的第 ii 位是否是由 00 变为 11 的。

不难想到当 cl,0=1c_{l,0}=1cr,1=1c_{r,1}=1 时,gl,rg_{l,r} 都会减少一。

还有当 cl+1,0cl,1=1c_{l+1,0}\lor c_{l,1}=1cr1,0cr,1=1c_{r-1,0}\lor c_{r,1}=1 时,gl,rg_{l,r} 也都会减少一。

所以判断这几种情况,就能算出 gl,rg_{l,r}

注意一些细节,具体见代码。

代码

#include<bits/stdc++.h>
using namespace std;
int T,n,q,a[200010];
bool f[200010][2];//这里的 f 即上文中的 c
char s[200010],t[200010];
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		scanf("%s",s+1);
		scanf("%s",t+1);
		for(int i=0;i<=n+1;i++) f[i][0]=f[i][1]=0;
		for(int i=2;i<n;i++){
			if(s[i-1]==s[i+1]&&s[i-1]=='0'){
				f[i][1]=(t[i]=='0');
				t[i]='1';
			}
		}
		for(int i=2;i<n;i++){
			if(t[i-1]==t[i+1]&&t[i-1]=='1'){
				f[i][0]=(s[i]=='0');
				s[i]='1';
			}
		}
		for(int i=1;i<=n;i++) a[i]=a[i-1]+(s[i]=='1');
		scanf("%d",&q);
		while(q--){
			int l,r;
			scanf("%d%d",&l,&r);
			int ans=a[r]-a[l-1];
			if(l==r){ //细节 1
				if(f[l][0]) ans--;
				printf("%d\n",ans);
				continue;
			}
			ans-=f[l][0]+f[r][0];
			if(r-l+1==2){//细节 2
				printf("%d\n",ans);
				continue;
			}
			if(l+1==r-1) ans-=(f[l+1][0]&f[l][1])|(f[r-1][0]&f[r][1]);//细节 3
			else ans-=(f[l+1][0]&f[l][1])+(f[r-1][0]&f[r][1]);
			printf("%d\n",ans);
		}
	}
	return 0;
}
posted @ 2024-06-18 16:03  fengxiaoyi  阅读(23)  评论(0)    收藏  举报  来源