*题解:P11218 【MX-S4-T2】「yyOI R2」youyou 不喜欢夏天
解析
考虑应该交换哪些列,应该是那些只选了一个 \(1\),而另一个元素是 \(0\) 的列,此时交换操作可以使最终连通块 \(1\) 的个数 \(-1\),\(0\) 的个数 \(+1\),对答案做 \(-2\) 的贡献。假设我们选了 \(k\) 个这样的列,那么就做了 \(-2\min(k,m)\) 的贡献。
一个朴素的想法就是把 \(k\) 设到状态里,无法通过。事实上我们可以讨论最终 \(\min(k,m)\) 的取值,若 \(\min(k,m) = k\),那么可以直接把 \(k\) 在选取的过程中算进贡献里,就算选了超过 \(m\) 个,也必定更劣,因为减了 \(2k > 2m\),且此种情况会在后面被考虑。否则 \(\min(k,m) = m\),可以不管选了多少个这样的列,最后统一 \(-2m\),选不满 \(m\) 个同样说明更劣,且此种情况会在前面被考虑。两种情况取 \(\max\) 即可。
故设 \(f_{i,00/01/10/11}\) 表示考虑了前 \(i\) 列,延伸到第 \(i\) 列的连通块,前一列没有选 / 选了第一行 / 选了第二行 / 两行都选了的贡献。跑两次 DP 即可,转移方程见代码。
时间复杂度 \(O(n)\)。
没想到的地方
分类讨论 \(\min(k,m)\)。
总结
尝试将贡献写成表达式。
看到最值尝试分类讨论。
代码
#include<bits/stdc++.h>
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
const int N = 2e6 + 5;
int f[N][4];
int a1[N],a2[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int c,T;
cin>>c>>T;
while(T--){
int n,m;
cin>>n>>m;
string s1,s2;
cin>>s1>>s2;
s1 = " " + s1;
s2 = " " + s2;
for(int i=1;i<=n;i++){
a1[i] = (s1[i] - '0') == 0 ? -1 : 1;
a2[i] = (s2[i] - '0') == 0 ? -1 : 1;
}
int res = 0;
for(int i=0;i<n;i++){
f[i + 1][0] = 0;
f[i + 1][1] = a1[i + 1] - 2 * (a1[i + 1] == 1 && a2[i + 1] == -1);
f[i + 1][2] = a2[i + 1] - 2 * (a1[i + 1] == -1 && a2[i + 1] == 1);
f[i + 1][3] = a1[i + 1] + a2[i + 1];
for(int j=1;j<4;j++){
if(j & 1){
f[i + 1][1] = max(f[i + 1][1],f[i][j] + a1[i + 1] - 2 * (a1[i + 1] == 1 && a2[i + 1] == -1));
}
if(j & 2){
f[i + 1][2] = max(f[i + 1][2],f[i][j] + a2[i + 1] - 2 * (a2[i + 1] == 1 && a1[i + 1] == -1));
}
f[i + 1][3] = max(f[i + 1][3],f[i][j] + a1[i + 1] + a2[i + 1]);
}
res = max({res,f[i + 1][0],f[i + 1][1],f[i + 1][2],f[i + 1][3]});
}
for(int i=0;i<n;i++){
f[i + 1][0] = 0;
f[i + 1][1] = a1[i + 1];
f[i + 1][2] = a2[i + 1];
f[i + 1][3] = a1[i + 1] + a2[i + 1];
for(int j=1;j<4;j++){
if(j & 1){
f[i + 1][1] = max(f[i + 1][1],f[i][j] + a1[i + 1] );
}
if(j & 2){
f[i + 1][2] = max(f[i + 1][2],f[i][j] + a2[i + 1]);
}
f[i + 1][3] = max(f[i + 1][3],f[i][j] + a1[i + 1] + a2[i + 1]);
}
res = max(res,max({f[i + 1][0],f[i + 1][1],f[i + 1][2],f[i + 1][3]}) - 2 * m);
}
cout<<res<<'\n';
}
return 0;
}

浙公网安备 33010602011771号