• 2018.11.07-4031-reverse


    题目描述:

    小G有一个长度为n的01串T,其中只有TS = 1,其余位置都是0。现在小G可以进行若干以下操作:

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

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

    输入:

    一行四个整数n,K,m,S。

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

    输入:

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

    数据范围:

    对于所有数据,有1≤n≤105,1≤S,k≤n,0≤m≤n。

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

    Subtask1(24%), n≤10。

    Subtask2(22%), n≤103。

    Subtask3(3%), k=1。

    Subtask4(8%), k=2。

    Subtask5(43%), 没有特殊的约束。

    算法标签:stl的使用,貌似并差集也可写吧

    思路:

    对于每个位置,可以更新的位置是一个区间内的奇数或偶数,所以用两个set存下分开存下奇数和偶数,每次把已访问的点出set,所以每个位置只会访问到一次。

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1e5+5;
    int n,k,s,m,d[N];bool f[N];
    set<int> t1,t2;queue<int> q;
    set<int>::iterator it1,it2,it;
    il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
    int main()
    {
        n=read();k=read();m=read();s=read();
        for(int i=1;i<=m;i++)f[read()]=1;
        for(int i=1;i<=n;i+=2)if(!f[i]&&i!=s)t1.insert(i);
        for(int i=2;i<=n;i+=2)if(!f[i]&&i!=s)t2.insert(i);
        q.push(s);for(int i=1;i<=n;i++)d[i]=-1;d[s]=0;
        if(k&1){
            while(!q.empty()){
                int x=q.front();q.pop();
                int l=max(x-k+1,1),r=min(n,x+k-1);
                l+=l-x+k-1;r+=r-x-k+1;
                if(x&1){
                    it1=t1.lower_bound(l);
                    it2=t1.upper_bound(r);
                    for(it=it1;it!=it2&&it!=t1.end()&&*it<=n;){
                        d[*it]=d[x]+1;q.push(*it);t1.erase(it++);
                    }
                }
                else{
                    it1=t2.lower_bound(l);
                    it2=t2.upper_bound(r);
                    for(it=it1;it!=it2&&it!=t2.end()&&*it<=n;){
                        d[*it]=d[x]+1;q.push(*it);t2.erase(it++);
                    }
                }
            }
        }
        else{
            while(!q.empty()){
                int x=q.front();q.pop();
                int l=max(x-k+1,1),r=min(n,x+k-1);
                l+=l-x+k-1;r+=r-x-k+1;
                if(x&1){
                    it1=t2.lower_bound(l);
                    it2=t2.upper_bound(r);
                    for(it=it1;it!=it2&&it!=t2.end()&&*it<=r;){
                        d[*it]=d[x]+1;q.push(*it);t2.erase(it++);
                    }
                }
                else{
                    it1=t1.lower_bound(l);
                    it2=t1.upper_bound(r);
                    for(it=it1;it!=it2&&it!=t1.end()&&*it<=r;){
                        d[*it]=d[x]+1;q.push(*it);t1.erase(it++);
                    }
                }
            }
        }
        for(int i=1;i<n;i++)printf("%d ",d[i]);printf("%d",d[n]);
      return 0;
    }
    View Code

    我的沙雕分讨

  • 相关阅读:
    层的问题,
    创建一个函数,返回元素个数为n的int型数组中的最小值
    c语言中编写函数求五个学生中的最高分
    c语言中没有形参的函数(例题:逆向输出正整数)
    创建一个函数,对元素个数为n的int型数组进行倒序排列。
    c语言 函数中数组的传递, 形参和实参。
    c语言中函数的传递和const类型的修饰符
    c语言中的文件作用域、函数原型声明、定义声明和非定义声明
    c语言中文件包含指令和头文件
    c语言中数组元素的线性查找
  • 原文地址:https://www.cnblogs.com/Jessie-/p/9925741.html
Copyright © 2020-2023  润新知