CF1468H 【K and Medians】
由题意可得通过每次操作可以消去$k-1$个数,因此对于$(n-m)\%(k-1)\ne 0$的情况必然是无解的,直接输出$NO$即可
考虑消去实现的充要条件:
显然消去的最后一步必然是以$b$序列中的某一元素为中位数进行的,即有解的充要条件为可以构造出以下情况:$\exists i\in [1,m]\ ,\ S.t.\ b_i$两侧各有$(k-1)/2$个不在$b$序列中的数
考虑有解状态的构造可能性:
若$i$为上述最后一次消去的中位数,则显然要求初始状态下小于$b_i$的应被消去的数个数大于等于$(k-1)/2$,同理大于$b_i$的也需满足同样条件
满足以上条件则必能通过对原序列进行的若干次消去达到有解状态,下面提供一种消去方案
设初始状态下小于$b_i$的应被消去的数有$x$个,大于$b_i$的应被消去的数有$y$个
若$x-(k-1)/2>=k-1$则对左侧进行若干次消去$k-1$个数的操作直到不等式不再成立,设此时小于$b_i$的应被消去的数有$x_0$个,$y$同理
由$x+y$为$k-1$的倍数可得$x_0+y_0$也为$k-1$的倍数,若$x=(k-1)/2$且$y=(k-1)/2$则已达到上述情况,否则左侧消去$x_0-(k-1)/2$个数,右侧消去$y_0-(k-1)/2$个数即可
答案的处理
对于每个数,只需通过上述充要条件$O(1)$判断是否能达到有解状态即可,总复杂度$O(n)$
代码
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const int maxn=2e5+10; int t,n,k,m,b[maxn]; int main() { scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&k,&m); for(int i=1;i<=m;i++) scanf("%d",&b[i]); if((n-m)%(k-1)) { printf("NO\n"); continue; } bool f=0; for(int i=1;i<=m;i++) if(b[i]-i>=(k-1)/2&&n-m+i-b[i]>=(k-1)/2) { printf("YES\n"),f=1; break; } if(!f) printf("NO\n"); } return 0; }