1. 程式人生 > >AGC019D Shift and Flip(枚舉)

AGC019D Shift and Flip(枚舉)

sin 有一個 print font turn main 最小 sum 產生

題意:給定兩個長度為n(n<=2000)的由0和1組成的字符串A和B,有三種操作

1:將A向左循環移一格

2:將B向右循環移一格

3:將一個b[i]為1的位置的a[i]改為(1 - a[i])

詢問將A變為B的最短操作次數。若A無法變為B,則輸出-1。

輸入描述:兩行,每行一個長度為n的只包含0和1的字符串

輸出描述:一行,一個整數表示最小的的操作次數.若無法從A變為B,則輸出-1.

輸入樣例:

1010

1100

輸出樣例:

3

解析:首先先判斷-1的情況,不難發現如果B全為0且A也全為0,那麽就輸-1。如果B全為0且A也全為0,那麽答案就是0。

再來看看如何計算答案。用L[i]表示A中第i個位置向左移多少個位置後才能在B中有一個1。R[i]表示A中第i個位置向右移多少個位置後在B中有1。

枚舉最終的結果A的狀態(即移動到了哪個位置),這樣進行修改操作的次數是固定的(A與B中每位不同的個數就是修改的次數)。

由上一步可以得出枚舉的狀態是由原狀態左移(或右移)幾個單位得到的,假設這個值是cnt。

以左移為例。對於每個點的L[i],如果L[i] <= cnt,那麽就不會產生多余的移動操作。可是若L[i] > cnt,那麽這個點可能由原位置向右移u個單位,再向左移動u+L[i]*2-cnt個單位的過程中更改的;也可能是在原位置向左移L[i]個單位後再向右移L[i]-cnt個單位的過程中更改的。所以對於每個點,它的值要麽是 向右的最大值*2+向左的最大值*2-cnt;要麽是 向左的最大值*2-cnt,從中取一個最小值即可。

對於右也是類似的操作。具體實現細節看代碼。

代碼如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int maxn=2005;
 7 int n,L[maxn],R[maxn],bj[maxn],mx,mi,ans;
 8 int tota,totb,len,que[maxn];
 9 char a[maxn],b[maxn];
10 
11 int
cmpL(int a,int b) { 12 return L[a]<L[b]; 13 } 14 15 int cmpR(int a,int b) { 16 return R[a]<R[b]; 17 } 18 19 int main() { 20 scanf("%s%s",a+1,b+1); n=strlen(a+1); 21 ans=2e9; 22 for (int i=1;i<=n;++i) { //求1的個數 23 if (a[i]==1) tota++; 24 if (b[i]==1) totb++; 25 } 26 if (!totb) { //判-1 27 if (!tota) return puts("0"),0; 28 return puts("-1"),0; 29 } 30 for (int i=1;i<=n;++i) { //預處理L[i]與R[i] 31 int ind=i,cnt=0; 32 while (b[ind]!=1) { 33 ind--; cnt++; 34 if (ind==0) ind=n; 35 } 36 L[i]=cnt; 37 ind=i; cnt=0; 38 while (b[ind]!=1) { 39 ind++; cnt++; 40 if (ind==n+1) ind=1; 41 } 42 R[i]=cnt; 43 } 44 for (int i=1;i<=n;++i) { //枚舉移動後左端點的最終位置 45 int ind,sum=0; //sum記錄需要修改的點的個數 46 if (i==1) ind=1; else ind=n-i+2; 47 for (int j=1;j<=n;++j) bj[j]=0; //bj[i]記錄i號點是否要修改 48 for (int j=1;j<=n;++j) { 49 if (a[ind]!=b[j]) sum++,bj[ind]=1; 50 ind++; if (ind>n) ind=1; 51 } 52 int cnt; //cnt表示向左移(或右移)的位數 53 if (i==1) cnt=0; else cnt=n-i+1; //cnt表示向左移的位數 54 len=0; 55 for (int j=1;j<=n;++j) 56 if (bj[j] && L[j]>cnt) que[++len]=j; 57 sort(que+1,que+1+len,cmpR); 58 mx=0; mi=2e9; 59 if (len>0) mi=min(mi,R[que[len]]*2+cnt); 60 for (int j=len;j>=1;--j) { 61 mx=max(mx,L[que[j]]); 62 if (j>1) mi=min(mi,R[que[j-1]]*2+mx*2-cnt); 63 } 64 if (len>0) mi=min(mi,mx*2-cnt); 65 if (!len) mi=cnt; 66 ans=min(ans,mi+sum); 67 cnt=i-1; len=0; //cnt表示向右移的位數 68 for (int j=1;j<=n;++j) 69 if (bj[j] && R[j]>cnt) que[++len]=j; 70 sort(que+1,que+1+len,cmpL); 71 mx=0; mi=2e9; 72 if (len>0) mi=min(mi,L[que[len]]*2+cnt); 73 for (int j=len;j>=1;--j) { 74 mx=max(mx,R[que[j]]); 75 if (j>1) mi=min(mi,L[que[j-1]]*2+mx*2-cnt); 76 } 77 if (len>0) mi=min(mi,mx*2-cnt); 78 if (!len) mi=cnt; 79 ans=min(ans,mi+sum); 80 } 81 printf("%d",ans); 82 return 0; 83 }

AGC019D Shift and Flip(枚舉)