ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 P7514 【[省选联考 2021 A/B 卷] 卡牌游戏】

2021-07-29 20:04:46  阅读:189  来源: 互联网

标签:P7514 return int 题解 mid 卡牌 翻面 inline 联考


[省选联考 2021 A/B 卷] 卡牌游戏

题目大意:

有 \(n\) 张卡牌,可以将至多 \(m\) 张卡牌翻面,求最后卡牌极差的最小值。

solution:

首先我想到二分答案:考虑 \(check\) 一个极差 \(x\) :

  • 要翻面的一定是该序列的前缀后缀。

  • 两种情况:

    1.枚举无需翻面区间的左端点。

    2.枚举无需翻面区间的右端点。

  • 确定一个端点后,另一个端点可以通过二分查找 。

  • 剩下的即为需翻面的区间,要注意以下几点:

    1. 翻面卡牌数不能超过 \(m\) 。
    2. 翻面后卡牌值仍在范围内(范围具体指,如枚举左端点,则范围为 $a[,l,] \(~\) a[,l,]+x$ )。

细节处理:

由于翻的一定是前缀后缀,可以用一个数组来存前后缀 \(\text{RMQ}\) 。刚开始我用了 \(\text{ST}\) 表但是 \(\text{T}\) 了三个点。

看到这的同学,可以自己去写代码了(tf口吻)

代码
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
template <class T>
inline T Max(const T x,const T y){return x>y?x:y;}
template <class T>
inline T Min(const T x,const T y){return x<y?x:y;}
const int N=1e6+5;
int n,m; 
int a[N],b[N];
int pmax[N],pmin[N],smax[N],smin[N];
inline void RMQ(){
	pmax[0]=0,pmin[0]=0x7fffffff;
	for(int i=1;i<=n;i++)
		pmax[i]=Max(b[i],pmax[i-1]),pmin[i]=Min(b[i],pmin[i-1]);
	smax[n+1]=0,smin[n+1]=0x7fffffff;
	for(int i=n;i>=1;i--)
		smax[i]=Max(b[i],smax[i+1]),smin[i]=Min(b[i],smin[i+1]);
}
inline int ef1(int l,int r,int x){
	while(l<r){
		int mid=l+r+1>>1;
		if(a[mid]>x) r=mid-1;
		else		 l=mid;
	}
	return r;
}
inline int ef2(int l,int r,int x){
	while(l<r){
		int mid=l+r>>1;
		if(a[mid]>=x) r=mid;
		else	      l=mid+1;
	}
	return r;
}
inline bool check(int x){
	for(int l=1,r;l<=n;l++){
		r=ef1(l,n,x+a[l]);
		if(n-(r-l+1)>m) continue;
		if(Min(pmin[l-1],smin[r+1])>=a[l]&&Max(pmax[l-1],smax[r+1])<=a[l]+x)
		 	return 1;
	}
	for(int r=1,l;r<=n;r++){
		l=ef2(1,r,a[r]-x);
		if(n-(r-l+1)>m) continue;
		if(Min(pmin[l-1],smin[r+1])>=a[r]-x&&Max(pmax[l-1],smax[r+1])<=a[r])
		 	return 1;
	}
	return 0;
}
signed main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	RMQ();
	int l=0,r=a[n]-a[1],ans;
	while(l<=r){
		int mid=l+r>>1;
		if(check(mid)) ans=mid,r=mid-1;
		else           l=mid+1;
	}
	printf("%d",ans);
	return 0;
}

证明一下

如下图:

我们把选好的中间一段反转:


若不出现翻转区间中 \(b[\,i\,]>a[\,n\,]\) 或者 \(b[\,i\,]<a[\,1\,]\) 的情况,易证不会对极差造成影响。

若出现上述情况,不妨设 \(b[\,j2\,]<a[\,1\,]\) ,此时极差为 \(a[\,n\,]-b[\,j2\,]\),该值一定大于 \(a[\,n\,]-a[\,1\,]\) ,不会作为最小值 。

根据上述结论,\(b[\,j1\,]>a[\,n\,]\) 时也不会出现更小的极差。

证毕

End

标签:P7514,return,int,题解,mid,卡牌,翻面,inline,联考
来源: https://www.cnblogs.com/TSZ-think/p/15076781.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有