[题目传送门](https://www.luogu.com.cn/problem/P10766)
## 思路:
首先,同类操作区间一定不相交(分为覆盖和取反)。
然后,对于一个覆盖和一个取反操作显然是可以颠倒顺序的。
发现以上性质之后就可以开始考虑 dp 了。
状态定义:$dp_{i,j}$ 表示前 $i$ 个已符合且最后一次用了 $j$ 号操作的最小步数($0,1,2$ 分别表示覆盖为 $0,1$ 和取反操作)。
状态转移方程:见代码。
答案:$\min{dp_{n,0},dp_{n,1},dp_{n,2}}$。
时间复杂度:$\mathcal{O(n)}$。
## code:
```cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=1e6+5;
int T,dp[MAXN][3];
char s[MAXN],t[MAXN];
signed main(){
cin>>T;
while(T--){
cin>>s+1>>t+1;
memset(dp,0x3f,sizeof(dp));
dp[1][0]=(t[1]=='1')+1;
dp[1][1]=(t[1]=='0')+1;
dp[1][2]=(t[1]!=s[1]);
int n=strlen(s+1);
for(int i=2;i<=n;i++){
if(t[i]=='0'){
dp[i][0]=min(dp[i-1][0],min(dp[i-1][1]+1,dp[i-1][2]+1));
}else{
dp[i][0]=min(dp[i-1][0]+(t[i-1]=='0'),min(dp[i-1][1]+(t[i-1]=='1')+1,dp[i-1][2]+(t[i-1]==s[i-1])+1));
}
if(t[i]=='1'){
dp[i][1]=min(dp[i-1][1],min(dp[i-1][0]+1,dp[i-1][2]+1));
}else{
dp[i][1]=min(dp[i-1][1]+(t[i-1]=='1'),min(dp[i-1][0]+(t[i-1]=='0')+1,dp[i-1][2]+(t[i-1]==s[i-1])+1));
}
if(t[i]==s[i]){
dp[i][2]=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));
}else{
dp[i][2]=min(dp[i-1][0]+(t[i-1]=='0'),min(dp[i-1][1]+(t[i-1]=='1'),dp[i-1][2]+(t[i-1]==s[i-1])));
}
}
cout<<min(dp[n][0],min(dp[n][1],dp[n][2]))<<endl;
}
return 0;
}
```
674

被折叠的 条评论
为什么被折叠?



