[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;
}

浙公网安备 33010602011771号