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;
}
posted @ 2021-02-09 22:54  Ivanovcraft  阅读(120)  评论(0编辑  收藏  举报