2018.11.07-4031-reverse
阿新 • • 發佈:2018-11-07
題目描述:
小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
保證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> #defineView Codeil 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);returnf*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; }
我的沙雕分討