• CF1468H 【K and Medians】


    由题意可得通过每次操作可以消去$k-1$个数,因此对于$(n-m)\%(k-1) e 0$的情况必然是无解的,直接输出$NO$即可

    考虑消去实现的充要条件:

    显然消去的最后一步必然是以$b$序列中的某一元素为中位数进行的,即有解的充要条件为可以构造出以下情况:$exists iin [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
    ");
                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
    "),f=1;
                    break;
                }
            if(!f)
                printf("NO
    ");
        }
        return 0;
    }
  • 相关阅读:
    day02_07 创建新目录
    day02_04 字典
    day02_02 列表切割
    day03_01 文件操作
    MS的TREE 控件使用
    使用自定义用户控件的一些经验
    Asp.net开发心得点滴[动态加载的用户控件使用事件委托,交给页面处理的事件无效问题]
    正则表达式基础学习[1]
    自定义控件无法在VS.net编辑中显示
    错误的递归
  • 原文地址:https://www.cnblogs.com/ivanovcraft/p/14394521.html
Copyright © 2020-2023  润新知