[省选联考 2021]卡牌游戏

卡牌游戏

题解

非常简单的一道题,数据水到直接拿最大值减最小值都能过

也就是去二分一下极差,然后看每个点作为最大的一个点时是否满足需要翻转的点数量小于 m m m
假设当前枚举到点的值为 x x x,也就是说所有正面不在 [ x − m i d , x ] [x-mid,x] [xmid,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;
}

谢谢!!!

posted @ 2021-04-17 16:57  StaroForgin  阅读(13)  评论(0)    收藏  举报  来源