1. 程式人生 > >【列舉】AGC019D Shift and Flip

【列舉】AGC019D Shift and Flip

分析:

終於有道簡單題了。。。

很顯然,可以列舉A位置最終對應到哪個位置。方便起見,可以把B陣列複製為三倍,然後就可以暴力枚舉了。先檢查每一位是否需要更改,如果需要,是否在其移動範圍內就能遇到一個 b i = 1 b_i=1

的位置。如果不能,向左向右至少走多少步。

現在可以得到:每個無法滿足的點需要向左/右移動的最小距離。

如果我們令向左最遠的一個走左邊,那麼剩下的都可以走左邊。如果向左最遠的一個不走左邊,其必須走右邊,那麼再來看次遠的一個走左還是右。這樣依次處理下去,就可以O(N)算出總的需要多走的左右步數。但需要排個序所以還是O(NlogN)的。

總的時間複雜度O(N^2logN)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector> #define SF scanf #define PF printf #define MAXN 2010 #define INF 0x3FFFFFFF using namespace std; char s[MAXN*3],s1[MAXN]; int pre[MAXN*3],nl[MAXN*3],nr[MAXN*3],ans=INF,len; vector<pair<int,int> > add; void prepare(){ nl[0]=-INF; for(int i=1;i<=len*3;i++){ nl[i]
=nl[i-1]; if(s[i]=='1') nl[i]=i; } nr[len*3+1]=INF; for(int i=len*3;i>=1;i--){ nr[i]=nr[i+1]; if(s[i]=='1') nr[i]=i; } for(int i=1;i<=len*3;i++) pre[i]=pre[i-1]+s[i]-'0'; } int findl(int x){ return min(INF,x-nl[x]); } int findr(int x){ return min(INF,nr[x]-x); } int main(){ SF("%s",s1+1); SF("%s",s+1); len=strlen(s+1); for(int i=len+1;i<=len*3;i++) s[i]=s[(i-1)%len+1]; prepare(); for(int i=1;i<=2*len+1;i++){ add.clear(); int sum=0; for(int j=1;j<=len;j++){ if(s1[j]!=s[i+j-1]){ sum++; int r=j+len; int l=j+i-1; if(l>r) swap(l,r); if(pre[r]-pre[l-1]==0) add.push_back(make_pair(findl(l),findr(r))); } } add.push_back(make_pair(0,0)); sort(add.begin(),add.end()); int adds=INF,maxv=0; for(int i=int(add.size()-1);i>=0;i--){ if(add[i].first!=INF&&maxv!=INF) adds=min(adds,maxv*2+add[i].first*2); maxv=max(maxv,add[i].second); if(maxv==INF) break; } if(adds!=INF) ans=min(ans,adds+abs(len+1-i)+sum); } if(ans==INF) ans=-1; PF("%d",ans); }