CF1592B Hemose Shopping 题解

题目传送门
题目大意:有一个长度为 \(n\) 的序列 \(a\) 和数字 \(x\) ,我们每次可以选定两个数 \(i,j\) 满足 \(x\le |i-j|\) ,然后交换 \(a_i,a_j\) 。请问经过若干次操作是否能让序列 \(a\) 递增。
题目解析:
我们发现当 \(x\le \lfloor \frac{n}{2} \rfloor\) 的时候显然是成立的,因为我们可以通过第三个数字造作三次来交换任意两个数字。
当然如果序列 \(a\) 是递增的话肯定能满足条件。

所以我们只要考虑 \(x>\lfloor \frac{n}{2} \rfloor\) 并且序列 \(a\) 不是单调递增的情况。这是我们发现有序列中间一部分的序列是不能动的,而其他部分的序列是可以随意交换的,方法类似于上面的方法的。
我们发现,这个时候序列中 \(a_{n-x+1},a_{n-x+2},\dots,a_x\) 这一段是不能移动的,而其他的都能任意交换。
所以需要不能移动的部分递增,能任意移动的部分可以通过移动保证序列递增就可以了。我们只需要统计能移动的部分小于等于 \(a_{n-x+1}\) 和大于等于 \(a_x\) 的数字的个数就可以了。当然注意考虑一下 \(a_{n-x+1}=a_x\) 的情况。

代码(去除了快读&一堆没用的宏定义&头文件):

int T,n,x,a[maxn];
int checkup(){
	for(RI i=1;i<n;i++) if(a[i]>a[i+1]) return 0;
	return 1;
}
int check(){
	if(x<=(n>>1)) return 1; if(x>=n) return checkup();
	RI i,cnt1=0,cnt2=0,minx=INF,maxx=-INF; x=n-x;
	for(i=x+1;i<=n-x;i++){
		maxx=max(maxx,a[i]); minx=min(minx,a[i]);
		if(i!=n-x&&a[i]>a[i+1]) return 0;
	}
	for(i=1;i<=x;i++)
		{ if(a[i]<minx) cnt1++; if(a[i]==minx) cnt2++; if(minx<a[i]&&a[i]<maxx) return 0; }
	for(i=n-x+1;i<=n;i++)
		{ if(a[i]<minx) cnt1++; if(a[i]==minx) cnt2++; if(minx<a[i]&&a[i]<maxx) return 0; }
	if(minx==maxx) return cnt1+cnt2>=x && cnt1<=x;
	return cnt1+cnt2==x;
}
int main(){
	T=read(); while(T--){
		n=read(); x=read(); for(RI i=1;i<=n;i++) a[i]=read();
		if(check()) puts("YES"); else puts("NO");
	}
	return 0;
}
posted @ 2021-10-05 11:33  jiangtaizhe001  阅读(95)  评论(0编辑  收藏  举报