[省选联考 2021]卡牌游戏
卡牌游戏
题解
非常简单的一道题,数据水到直接拿最大值减最小值都能过
也就是去二分一下极差,然后看每个点作为最大的一个点时是否满足需要翻转的点数量小于
m
m
m。
假设当前枚举到点的值为
x
x
x,也就是说所有正面不在
[
x
−
m
i
d
,
x
]
[x-mid,x]
[x−mid,x]之内的点全部需要翻面,如果翻面后还有点不在这个范围之内,那么我们就只能这个点就铁定不行。
关于维护那些点不在这个范围内,因为我们枚举的最大值是递增的,我们可以将
a
a
a排序后用指针维护。关于翻面后是否有值不在这个范围内,我们可以用前后缀最大/小值维护。
需要注意的就是当枚举
b
i
b_{i}
bi的作为最大值时,要考虑
a
i
a_{i}
ai是否在范围内。
总时间复杂度 O ( n l o g n ) O\left(nlog\,n\right) O(nlogn)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<time.h>
using namespace std;
#define MAXN 1000005
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef unsigned int uint;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,prex[MAXN],pren[MAXN],sufx[MAXN],sufn[MAXN];
struct ming{int a,b;}s[MAXN],d[MAXN];
bool check(int mid){
int l=0,r=0;bool fg=0;
for(int i=1;i<=n;i++){
while(l<n&&s[l+1].a<s[i].a-mid)l++;
while(r<=n&&s[r].a<=s[i].a)r++;bool flag=0;
if(l>0&&(prex[l]>s[i].a||pren[l]<s[i].a-mid))flag=1;
if(r<=n&&(sufx[r]>s[i].a||sufn[r]<s[i].a-mid))flag=1;
if(l+n-r+1>m)flag=1;if(!flag){fg=1;break;}
}
if(fg)return 1;l=0;r=0;
for(int i=1;i<=n;i++){
while(l<n&&s[l+1].a<d[i].b-mid)l++;
while(r<=n&&s[r].a<=d[i].b)r++;bool flag=0;
if(l>0&&(prex[l]>d[i].b||pren[l]<d[i].b-mid))flag=1;
if(r<=n&&(sufx[r]>d[i].b||sufn[r]<d[i].b-mid))flag=1;
if(l+n-r+1-(d[i].a<d[i].b-mid)-(d[i].a>d[i].b)>m-1)flag=1;if(!flag){fg=1;break;}
}
return fg;
}
bool cmp(ming x,ming y){return x.b<y.b;}
signed main(){
read(n);read(m);for(int i=1;i<=n;i++)read(s[i].a);for(int i=1;i<=n;i++)read(s[i].b),d[i]=s[i];sort(d+1,d+n+1,cmp);
pren[1]=prex[1]=s[1].b;for(int i=2;i<=n;i++)pren[i]=min(pren[i-1],s[i].b),prex[i]=max(prex[i-1],s[i].b);
sufx[n]=sufn[n]=s[n].b;for(int i=n-1;i>0;i--)sufn[i]=min(sufn[i+1],s[i].b),sufx[i]=max(sufx[i+1],s[i].b);
int l=0,r=1e9;while(l<r){int mid=l+r>>1;if(check(mid))r=mid;else l=mid+1;}
printf("%d\n",l);
return 0;
}

浙公网安备 33010602011771号