【题解】D. Cheater
背景
赛时左右脑互博 \(1\) 小时后才过 B,遂直接看了 D。
题意
两个人在玩游戏,每个人有 \(n\) 张写有不同数字的牌,每个人都按顺序出牌,数字大的那一方赢,然后打出下一张牌并继续于另外一人的牌比较,比较一共进行 \(n\) 轮,问现在有一个人能交换两张自己的牌,最多一次,问这个人能获得的最大分数。
思路
我们注意到一共只会比较 \(n\) 轮,所以我们可以考虑枚举对方最少能活动多少分,我们假设对手得分 \(x\) 分,意味着我方前 \(n-x\) 牌必须出完,我们注意到当对手目前的牌为前 \(x\) 张的最小牌时,如果我方还没有出不了前 \(n-x\) 张牌,那么我方一定无法获得 \(n-x\) 分。
证明:对手的最小牌我方都出不了牌,那么对手往后的牌我方也一定出不了。
我们考虑我方那些牌会使我方在对手最小牌时出不了,显然是那些小于对手的最小牌的,于是我们对这一张牌与我们不需要出的牌的最大的牌交换,然后看是否还有我们出不了的牌,体现就是小于对手的最小牌的数量不能大于等于 \(2\) 张。
但是直接做复杂度是 \(O(n^2)\) 的我们考虑优化。
我们可以二分出来这个 \(x\),然后就做完了,复杂度 \(O(n \log n)\)。
代码
点击查看代码
// Problem: D. Cheater
// Contest: Codeforces - Codeforces Round 1031 (Div. 2)
// URL: https://codeforces.com/contest/2113/problem/D
// Author: Air2011
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 循此苦旅,直抵群星!
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Air
namespace io{
inline int read(){
int f=1,t=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch>='0'&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
return t*f;
}
inline void write(int x){
if(x<0){putchar('-');x=-x;}
if(x>=10){write(x/10);}
putchar(x%10+'0');
}
}
using namespace io;
int n;
const int N=2e5+10;
int a[N];
int b[N];
bool check(int x){
int kk=1e18;
for(int i=1;i<=x+1;i++){
kk=min(kk,b[i]);
}
int cnt=0;
for(int i=1;i<=n-x;i++){
if(a[i]<=kk){
cnt++;
if(cnt>=2)return 0;
}
}
if(cnt==0){
return 1;
}
int maxx=0;
for(int i=n-x+1;i<=n;i++){
maxx=max(maxx,a[i]);
}
return maxx>kk;
}
void work(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
for(int j=1;j<=n;j++){
b[j]=read();
}
int l=0,r=n,mid;//让对手拿mid分
int res=0;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)){
res=mid;
r=mid-1;
}
else{
l=mid+1;
}
}
write(n-res);
putchar('\n');
}
signed main() {
#ifndef Air
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
int TCS=read();
while(TCS--){
work();
}
return 0;
}

浙公网安备 33010602011771号