题解:P12353 「HCOI-R2」DataErr0r
前言
怎么数据这么强的,dp 少写了一个转移式直接 0 分 \xia
思路分析
考虑一个无脑 DP,设 \(f_{i,0/1,0/1,0/1}\) 表示考虑 \(b\) 数组的前 \(i\) 位,是否已经出现过失配,奇数位之前是否已经取反,偶数位之前是否已经取反的最小操作次数。
转移比较硬核,不再一一列举,大概思路是分当前位是是否有 \(a_i=b_i\),以及下标的奇偶进行转移。具体转移方式可参照代码实现,应该写的比较详细。
这里只强调一种转移:
\[f_{i+1,1,l2,l1}\leftarrow f_{i,0,l1,l2}
\]
失配时,我们可以选择先进行取反操作,再进行删除,这样 \(l1,l2\) 会反转,因为删除后下标奇偶性反转。
复杂度 \(O(n)\)。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
int t,n,ans,f[1000005][2][2][2];
char a[1000005],b[1000005];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n+1;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int i=1;i<=n+1;i++){
for(int l1=0;l1<=1;l1++){
for(int l2=0;l2<=1;l2++){
f[i][0][l1][l2]=f[i][1][l1][l2]=inf;
}
}
}
f[1][0][0][0]=0;
for(int i=1;i<=n;i++){
for(int l1=0;l1<=1;l1++){
for(int l2=0;l2<=1;l2++){
f[i][1][l1][l2]=min(f[i][1][l1][l2],f[i][0][l1][l2]);
f[i][1][l2][l1]=min(f[i][1][l2][l1],f[i][0][l1][l2]);
}
}
for(int l1=0;l1<=1;l1++){
for(int l2=0;l2<=1;l2++){
f[i][1][l1][l2]=min(f[i][1][l1][l2],f[i][0][l1][l2]);
f[i][1][l2][l1]=min(f[i][1][l2][l1],f[i][0][l1][l2]);
if(i&1){
if(a[i]==b[i]) f[i+1][0][0][l2]=min(f[i+1][0][0][l2],f[i][0][l1][l2]);
else f[i+1][0][1][l2]=min(f[i+1][0][1][l2],f[i][0][l1][l2]+(!l1));
if(a[i+1]==b[i]) f[i+1][1][0][l2]=min(f[i+1][1][0][l2],f[i][1][l1][l2]);
else f[i+1][1][1][l2]=min(f[i+1][1][1][l2],f[i][1][l1][l2]+(!l1));
}else{
if(a[i]==b[i]) f[i+1][0][l1][0]=min(f[i+1][0][l1][0],f[i][0][l1][l2]);
else f[i+1][0][l1][1]=min(f[i+1][0][l1][1],f[i][0][l1][l2]+(!l2));
if(a[i+1]==b[i]) f[i+1][1][l1][0]=min(f[i+1][1][l1][0],f[i][1][l1][l2]);
else f[i+1][1][l1][1]=min(f[i+1][1][l1][1],f[i][1][l1][l2]+(!l2));
}
}
}
}
ans=inf;
for(int l1=0;l1<=1;l1++){
for(int l2=0;l2<=1;l2++){
ans=min(ans,f[n+1][0][l1][l2]);
ans=min(ans,f[n+1][1][l1][l2]);
}
}
cout<<ans+1<<'\n';
}
return 0;
}