题解:P12353 「HCOI-R2」DataErr0r
upd:数据更新。
注意到
所以就可以把题意转化为把
考虑预处理出
但是还需要注意:拼接成新字符串后,前后字符串的操作
我们可以发现操作合并只对当前字符后的字符串的前两位即
考虑一种特殊情况(讨论区大佬的 hack):
1 7
00000000
1110001
当删除第 4 位时,可以通过删除字符前后下标奇偶性改变的性质将前缀字符串的操作延伸到前后操作
先将操作
00000000
->01010101
然后删除第 4 位字符,
->0100101
最后再次取反,将后缀字符串前不需要改变的字符变回来。
->1110001
那怎么判断这种情况呢?
当
代码中怎么实现呢?
预处理出两个数组
注意数组
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,pre[N],ne[N],pre_id[N],ne_id[N];
char x[N],y[N];
int main(){
int t;
cin>>t;
while(t--){
cin>>n>>x+1>>y+1;
int ans=1e9;
bool flag[2]={0,0};
for(int i=1;i<=n;i++){
pre[i]=pre[i-1];
pre_id[i]=pre_id[i-1];
if(x[i]==y[i]) flag[i%2]=0;
else{
pre_id[i]=i;
if(!flag[i%2]) pre[i]++;
flag[i%2]=1;
}
}
flag[1]=flag[0]=0;
ne[n+2]=0;
ne_id[n+2]=ne_id[n+3]=n+2;
for(int i=n+1;i>=2;i--){
ne[i]=ne[i+1];
ne_id[i]=ne_id[i+1];
if(x[i]==y[i-1]) flag[i%2]=0;
else{
ne_id[i]=i;
if(!flag[i%2]) ne[i]++;
flag[i%2]=1;
}
}
for(int i=1;i<=n+1;i++){
int res=pre[i-1]+ne[i+1]+1,p1=pre_id[i-1],p2=pre_id[i-2],n1=ne_id[i+1],n2=ne_id[i+2];
//删前
ans=min(ans,res-(i-1>=1&&x[i-1]!=y[i-1]&&i+1<=n+1&&x[i+1]!=y[i])-(i-2>=1&&x[i-2]!=y[i-2]&&i+2<=n+1&&x[i+2]!=y[i+1]));
//删后
ans=min(ans,res-(i-2>=1&&x[i-2]!=y[i-2]&&i+1<=n+1&&x[i+1]!=y[i])-(i-1>=1&&x[i-1]!=y[i-1]&&i+2<=n+1&&x[i+2]!=y[i+1]));
//特殊情况
if(i-2>=1&&p1==i-1&&p2==i-2){
if(n1<=n+1) res--;
else if(n2<=n+1) res--;
}
else if(i+2<=n+1&&n1==i+1&&n2==i+2){
if(p1) res--;
else if(p2) res--;
}
ans=min(ans,res);
}
cout<<ans<<endl;
}
return 0;
}