题目描述:
小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; }
我的沙雕分讨