*题解:CF2229D Me When Median Problem
解析
首先,由于操作始终会使 \(a\) 的某两个位置被 \(s_2\) 替换且 \(s_2\le s_3\),所以当 \(n > 1\) 时,最终的答案 \(\min(a_1,b_1)=a_1\)。
考虑二分答案 \(x\),这样 \(a,b\) 中大于等于 \(x\) 的数本质相同, 小于等于 \(x\) 的数也本质相同,所以不妨将其分别设为 \(1\) 和 \(0\)。这样,问题转化为在 0 / 1 序列上求解。
先一位一位考虑,发现只有当 \(a_i=1\) 且 \(b_i=1\) 时,对 \(i\) 或 \(i - 1\) 进行操作后才有可能使最终的 \(s_2,s_3\) 不含 \(0\)。对于 \(i\) 左边的不存在 \(a_j=1\) 且 \(b_j=1\) 的极长连续段,对其充分进行操作,最后剩下的 \(a,b\) 中必定有 \(1\) 个或 \(2\) 个为 \(0\)。二者区别在于是否存在 \(a_j=b_j=0\)。
定义两个多集 \(\{a,b\},\{c,d\}\) 之间进行配对操作的结果为对 \(S=\{a,b,c,d\}\) 进行操作后 \(s_2,s_3\) 组成的多集 \(\{s_2,s_3\}\)。对于剩下 \(\{0,1\}\) 的情况,直接配对就可以把这个 \(0\) 抹除,得到 \(\{1,1\}\)。否则操作后会变为 \(\{0,1\}\),还需要跟一个 \(\{1,1\}\) 配对才能把 \(0\) 抹除。由于 \(\{0,1\}\) 跟 \(\{0,1\}\) 配对还是 \(\{0,1\}\),所以可以把所有 \(\{0,1\}\) 配对完之后再跟一个 \(\{1,1\}\) 配对。这样,需要 \(\{1,1\}\) 的个数为不存在 \(a_i=b_i=1\) 且存在 \(a_i=b_i=0\) 的极长连续段个数加 \(1\)。
时间复杂度 \(O(n \log n)\)。
代码
/*
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 2e5 + 5,M = 10 + 5,L = 19,L2 = 17,mod = (int)1e9 + 7;
int a[N],b[N],c[N],d[N];
int n;
bool chk(int x){
int cnt0 = 0,cnt1 = 0,pre = 1;
for(int i=1;i<=n;i++){
c[i] = a[i] >= x;
d[i] = b[i] >= x;
int cnt = c[i] + d[i];
if(cnt == 0){
if(pre != 0){
cnt0++;
pre = 0;
}
}else if(cnt == 2){
pre = 1;
cnt1++;
}
}
return cnt1 > cnt0;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
int l = 1,r = 2 * n;
while(l < r){
int mid = (l + r + 1) >> 1;
if(chk(mid)){
l = mid;
}else{
r = mid - 1;
}
}
cout<<l<<'\n';
}
return 0;
}

浙公网安备 33010602011771号