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;
}