zoukankan      html  css  js  c++  java
  • 雅礼集训 Day7 T1 Equation 解题报告

    Reverse

    题目背景

    ( ext{G})有一个长度为(n)(01)(T),其中只有(T_S=1),其余位置都是(0)。现在小( ext{G})可以进行若干次以下操作:

    • 选择一个长度为(K)的连续子串((K)是给定的常数),翻转这个子串。

    对于每个(i,iin [1,n]),小( ext{G})想知道最少要进行多少次操作使得(T_i=1).特别的,有(m)个“禁止位置”,你需要保证在操作过程中(1)始终不在任何一个禁止位置上。

    输入输出格式

    输入格式

    从文件reverse.in中读入数据.

    第一行四个整数(n,K,m,S).

    接下来一行(m)个整数表示禁止位置。

    输出格式

    输出到文件reverse.out中.

    输出一行(n)个整数,对于第(i)个整数,如果可以通过若干次操作使得(T_i=1),输出最小操作次数,否则输出(-1).

    说明

    对于所有数据,有(1≤n≤10^5,1≤S,k≤n,0≤m≤n).

    保证(S)不是禁止位置,但禁止位置可能有重复。

    • ( ext{Subtask1}(24\%), n≤10).

    • ( ext{Subtask2}(22\%), n≤10^3).

    • ( ext{Subtask3}(3\%), k=1).

    • ( ext{Subtask4}(8\%), k=2).

    • ( ext{Subtask5}(43\%)), 没有特殊的约束。


    题目其实并不难

    发现可以连边直接bfs,可以拿到57pts的暴力分

    发现边的数量很多,需要支持动态删点

    用两颗平衡树分别维护位置为奇数时和位置为偶数时

    然后每次找到可翻转的左边和右边,在平衡上二分,bfs然后删掉点就可以了

    每个点只会被删掉一次,复制度差不多是(O(nlogn))


    Code:

    #include <cstdio>
    #include <cstring>
    #include <set>
    const int N=1e5+10;
    std::set <int> s1,s2;
    std::set <int>::iterator it;
    int n,k,m,s,l=1,r,q[N<<2],used[N],ans[N],lp,rp,d;
    int min(int x,int y){return x<y?x:y;}
    int max(int x,int y){return x>y?x:y;}
    int main()
    {
        scanf("%d%d%d%d",&n,&k,&m,&s);
        memset(ans,-1,sizeof(ans));
        used[s]=1,q[++r]=s,ans[s]=0;
        for(int p,i=1;i<=m;i++) scanf("%d",&p),used[p]=1;
        for(int i=1;i<=n;i+=2)
        {
            if(!used[i]) s1.insert(i);
            if(!used[i+1]) s2.insert(i+1);
        }
        while(l<=r)
        {
            int p=q[l++];
            lp=max(p-k+1,max(k-p+1,1)),rp=min(p+k-1,min(2*n+1-k-p,n));
            if(p-k&1)//s2
            {
                it=s2.lower_bound(lp);
                while(it!=s2.end()&&(d=*it)<=rp)
                {
                    q[++r]=d;
                    ans[d]=ans[p]+1;
                    it++;
                    s2.erase(d);
                }
            }
            else
            {
                it=s1.lower_bound(lp);
                while(it!=s1.end()&&(d=*it)<=rp)
                {
                    q[++r]=d;
                    ans[d]=ans[p]+1;
                    it++;
                    s1.erase(d);
                }
            }
        }
        for(int i=1;i<=n;i++)
            printf("%d ",ans[i]);
        return 0;
    }
    
    

    2018.10.7

  • 相关阅读:
    LVGL初步移植
    为什么javac后加.java,java后不加.class?
    为什么内部类可以访问外部类的私有属性?
    Optional类与使用==判断null有什么区别?使用Optional类有什么优势?
    注释中的Unicode编码也会被转义
    用反射编写泛型数组
    JDBC与JPA--初学JPA
    抽象类与接口
    面向对象——多态
    面向对象——封装(隐藏)
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9750752.html
Copyright © 2011-2022 走看看