题解:CF2225C Red-Black Pairs

· · 题解

很裸的一个 dp。

给你一个 $2\times n$ 的矩阵,每个格子有一个颜色 `R` 或 `B`。你需要将这 $n\times2$ 个格子两两配对,使配对的两个格子相邻并且颜色相同。问至少改变多少个格子的颜色才能存在一组可能的配对方案。 发现前面的格子怎么配对不会影响后面的格子,满足无后效性。考虑 dp。 设 $f_i$ 表示前 $i$ 列的格子全部配对完的最小花费。 :::success[为什么可以一列一列的配对] 如果不是一列一列配对的话,就只有如下这种情况: ``` ?BB RR? ``` 如果我们像上面一样配对的话,左边剩下的和右边剩下的都是奇数个,无法全部配对。所以同一列的格子一定是相互配对或并排配对的。 ::: 我们按照一列或两行的配对来转移: 1. 如果到第 $i$ 列要竖着配对,则判断这一列的格子颜色是否相同即可。如果不同则需要付出 $1$ 的花费。状态转移方程为 $f_i\leftarrow f_{i-1}+[a_{1,i}\neq a_{2,i}]$。 2. 如果到第 $i$ 列要横着配对,则需要分别判断第 $1$ 行两个格子是否同色,第 $2$ 行两个格子是否同色即可。状态转移方程为 $f_i\leftarrow f_{i-2}+[a_{1,i-1}\neq a_{1,i}]+[a_{2,i-1}\neq a_{2,i}]$。 答案即为 $f_n$。 :::success[[$\text{\color{green}Accepted code}$](https://codeforces.com/contest/2225/submission/372088438)] ``` #include<bits/stdc++.h> #define int long long using namespace std; int read(){int x;cin>>x;return x;} void write(int x){cout<<x;} const int N=1000002; int t,n,a[4][N],f[N]; inline void work()noexcept { n=read(); for(int i=1;i<=n;i=-~i) { char ch; cin>>ch; a[1][i]=(ch=='R'?1:0),f[i]=0; } for(int i=1;i<=n;i=-~i) { char ch; cin>>ch; a[2][i]=(ch=='R'?1:0); } f[0]=0; for(int i=1;i<=n;i=-~i) { if(a[1][i]==a[2][i])f[i]=f[i-1]; else f[i]=f[i-1]+1; if(i!=1) { int sum=f[i-2]; if(a[1][i]!=a[1][i-1])sum++; if(a[2][i]!=a[2][i-1])sum++; f[i]=min(f[i],sum); } } write(f[n]),putchar('\n'); } signed main() { t=read(); while(t--)work(); return 0; } ``` ~~你发现上面的 AC 能点了吗。~~ :::