Codeforces
题解
]
CF2113D Cheater
由于所有牌的数字形成排列,互不相同,所以不用考虑数字相同的情况。
每次比较后,大的那张牌会放逐,小的那张牌会被留下。
因此,每次放逐的牌的大小是单调递减的,因为小的那张牌会被留下。无论对面下一张牌比它大还是比它小,放逐的牌都比前一次小。
另外,一个玩家得分数量代表他放逐的牌的数量。
注意到游戏只会进行 $n$ 轮,因此如果庄家得了 $x$ 分,那玩家就得了 $n-x$ 分,也就是庄家放逐了前 $x$ 张牌,玩家放逐了前 $n-x$ 张牌,我们要最小化 $x$。
不妨想想如果给定一个 $x$,能不能去判断庄家的得分 $\le x$,这样就可以二分答案了。
庄家放逐了前 $x$ 张牌,因此其前 $x+1$ 张牌参与了比较,而玩家前 $n-x$ 张牌被放逐了。
记庄家前 $x+1$ 张牌中最小的那张牌为 $k$,如果玩家前 $n-x$ 张牌中每张牌都 $>k$,那么玩家的所有牌都能出掉,庄家的出牌数量就会 $\le x$,即得分 $\le x$。
如果玩家前 $n-x$ 张牌中有一张牌 $<k$,不妨贪心,把玩家 $[n-x+1,n]$ 中最大的那张牌和这张牌进行交换,如果交换后 $>k$ 则仍可以。否则,这张牌会一直卡住,玩家出牌数量未满 $n-x$,庄家就出了超过 $x$ 张牌了。
如果玩家前 $n-x$ 张牌中有至少两张牌 $<k$,此时一定会卡住,不合法。
#include<bits/stdc++.h>
#define siz(x) int((x).size())
#define all(x) std::begin(x),std::end(x)
#define fi first
#define se second
using namespace std;
using unt=unsigned;
using loli=long long;
using lolu=unsigned long long;
using pii=pair<int,int>;
mt19937_64 rng(random_device{}());
constexpr int N=4e5+7;
int n,a[N],b[N];
bool check(int x){
int k=*min_element(b+1,b+1+x+1);
int cnt=0;
for(int i=1;i<=n-x;i++)
if(a[i]<k&&++cnt>=2)return 0;
if(cnt==0)return 1;
return (x?*max_element(a+n-x+1,a+n+1):0)>k;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);
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=0,r=n-1,mid,ans=n;
while(l<=r){
mid=((l+r)>>1);
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
cout<<n-ans<<'\n';
}
return 0;
}