[USACO1.1]壞掉的項鍊Broken Necklaceios
22892 破碎的項鍊spa
方法一:很容易想到枚舉斷點,再分別兩頭找,可是要注意不少細節code
#include<iostream> #include<string> #include<cstdio> using namespace std; string s; int n,l,r,ll,rr,tmp,ans; inline int calc(int x) { ll=s[x],rr=s[x+1],l=x-1,r=x+2; if (rr=='w') {//若是是w,需分類討論(如10 rwrwbwrwrw,答案爲10,去掉後輸出9) rr='r',tmp=x+2; while((s[tmp]=='w' || s[tmp]==rr) && tmp<x+n) tmp++; rr='b'; } while((s[l]=='w' || s[l]==ll) && l>x-n) l--; while((s[r]=='w' || s[r]==rr) && r<x+n) r++; return max(r,tmp)-l-1; } int main() { cin>>n>>s; s=s+s+s; for (int i=n; i<n+n; i++)//複製了三段,從中間一段枚舉斷點 if (s[i]!=s[i+1] && s[i]!='w')//當s[i]==s[i+1]時,在i+1計算比在i更優 ans=max(ans,calc(i)); if (s[n+n-1]==s[n+n]) ans=max(ans,calc(n+n-1));//若是都是同一顏色,則最後一個答案沒有計算(如3 rrr,去掉min答案就變成0) printf("%d",min(ans,n));//若是都是同一顏色,則結果不該超過n,(如3 rrr,去掉min答案就變成5) }
方法二:一邊作一邊統計答案(思路來自這個博客)blog
#include<cstring> #include<cstdio> #include<iostream> using namespace std; char s[700],c; int n,l,r,w,ans; /* l:左段長度,r:右段長度 w:連續w段的長度 c:當前段的顏色 */ int main() { scanf("%d%s",&n,s); memcpy(s+n,s,n); for (int i=0; i<n<<1; i++) if (s[i]=='w') w++,r++; else if (s[i]==c) w=0,r++; else ans=max(ans,l+r),l=r-w,r=w+1,w=0,c=s[i]; //這裏不能寫爲l=r,r=1,要把w段給右邊,這樣在下次修改答案時l更大 //如:bwrrb,遇到第一個r時應當把w給右邊,即l=r-w=1,r=w+1=2,這樣到第二個b時l更新爲3 //而若是用l=r=2,r=1, 第二個b時l更新爲2(把開頭的w捨去了) printf("%d",min(max(ans,l+r),n)); }
方法三:dp(思路來自這個博客)ci
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int n,lb[701],lr[701],rb[701],rr[701],ans;//l[i]不包括i,r[i]包括i char s[701]; int main() { scanf("%d%s",&n,s),memcpy(s+n,s,n),n<<=1; for (int i=1; i<n; i++) if (s[i-1]=='b') lb[i]=lb[i-1]+1; else if (s[i-1]=='r') lr[i]=lr[i-1]+1; else lb[i]=lb[i-1]+1,lr[i]=lr[i-1]+1; for (int i=n-2; i>=0; i--) if (s[i]=='b') rb[i]=rb[i+1]+1; else if (s[i]=='r') rr[i]=rr[i+1]+1; else rb[i]=rb[i+1]+1,rr[i]=rr[i+1]+1; for (int i=0; i<n; i++) ans=max(ans,max(lb[i],lr[i])+max(rb[i],rr[i])); printf("%d",min(ans,n>>1)); }