容易发现:
对于形如 \(00\) 或 \(11\) 的位置,热头发选择两个 \(0\) 或一个 \(1\) 一定不优,而热台风选择这个位置一定不优。
对于形如 \(01\) 的位置,若热头发仅选择 \(0\) 则一定不优,而若热头发仅选择 \(1\),热台风能选就直接选这个位置一定不劣。
不妨记热头发对于形如 \(01\) 的位置仅选择 \(1\) 的位置的数量为 \(cnt\),其余位置的贡献为 \(sum\)。
则若 \(cnt \le m\) 则答案为 \(sum-cnt\),否则答案为 \(sum+cnt-2m\)。
发现上式可以直接合并,而无须考虑 \(m\) 的范围,于是答案为 \(\max\{sum-cnt,sum+cnt-2m\}\)。而这两个式子独立,所以分别最大化这两个式子即可。
对于最大化 \(sum-cnt\),可以对于所有的 \(01\) 位置选和 \(11\) 位置,两个数都选,而 \(00\) 则只选 \(1\) 个。
对于最大化 \(sum+cnt-2m\),发现直接贪心有后效性,所以不妨记一下 \(0/1\) 表示当前下标选/不选某一行,则一共有三个状态,直接 \(dp\) 即可。
代码:
#include
using namespace std;
const int INF = 1e9;
const int N = 2e6+5;
int a[N][2];
int main(){freopen("game.in","r",stdin);freopen("game.out","w",stdout);cin.tie(nullptr)->sync_with_stdio(false);int c,t;cin>>c>>t;while(t--){int n,m;cin>>n>>m;for(int i=0;i<2;i++) for(int j=1;j<=n;j++){char c;cin>>c;a[j][i] = (c^0x30);}int ans = 0,sum = 0,mn = 0;for(int i=1;i<=n;i++){if(a[i][0]&&a[i][1]) sum+=2;else if(!a[i][0]&&!a[i][1]) sum--;mn = min(mn,sum),ans = max(ans,sum-mn);}mn = 0;pair now = make_pair(0,0);for(int i=1;i<=n;i++){if(!a[i][0]&&!a[i][1]) now.first--,now.second--;else if(a[i][0]&&a[i][1]){sum = max(now.first,now.second)+2;now.first = now.second = sum;}else if(a[i][0]) now = make_pair(max(now.first+1,now.second),max(now.first,now.second));else now = make_pair(max(now.first,now.second),max(now.first,now.second+1));sum = max(now.first,now.second);mn = min(mn,sum),ans = max(ans,sum-mn-m*2);}cout<