這道題數據規模奇小,所以大部分人都使用了暴力搜索的方法,這也是我一開始的想法。html
對於 的數據, web
的確能夠如此,但暴力搜索的方法也須要進行一些奇怪的判斷,所以我又決定直接打dp的解法,其實dp也是很天然的一種想法……數組
咱們能夠發現,每一個點向左向右,取藍色取紅色能連續取的個數必定是肯定的。
因而咱們定義dp數組:app
int lr[maxn]; //lr[i]表明從i點向左不取i點 //即在 [1,i-1] 範圍內從i-1開始能連續取多少個紅色珠子 int lb[maxn]; //lb[i]表明從i點向左不取i點 //即在 [1,i-1] 範圍內從i-1開始能連續取多少個藍色珠子 int rr[maxn]; //rr[i]表明從i點向右取i點 //即在[i,n] 範圍內從i開始能連續取多少個紅色珠子 int rb[maxn]; //rb[i]表明從i點向右取i點 //即在[i,n] 範圍內從i開始能連續取多少個藍色珠子
那麼在一個點斷開,能取得的珠子個數就是:
svg
相信轉移方程很是天然吧,咱們先考慮向左取的狀況:spa
爲何考慮前一個點呢?
由於
和
表明的是區間
內從點
開始取能連續取多少,所以實際考慮的是點
的顏色。
向右的狀況也是同理,有:code
for (int i = 2; i <= n; ++i) { if (s[i - 1] == 'w') lb[i] = lb[i - 1] + 1, lr[i] = lr[i - 1] + 1; else if (s[i - 1] == 'b') lb[i] = lb[i - 1] + 1, lr[i] = 0; else lb[i] = 0, lr[i] = lr[i - 1] + 1; } for (int i = n - 1; i; --i) { if (s[i] == 'w') rb[i] = rb[i + 1] + 1, rr[i] = rr[i + 1] + 1; else if (s[i] == 'b') rb[i] = rb[i + 1] + 1, rr[i] = 0; else rb[i] = 0, rr[i] = rr[i + 1] + 1; }
因而咱們處理出了每一個點向左向右取紅取藍最多能連續取多少個珠子。
那麼從
點,向左最多能取多少呢?
從
點,向右最多能取
假定咱們斷開
和
,那麼答案就是:
即
最後掃一遍統計答案便可。xml
int ans = 0; for (int i = 1; i <= n; ++i) ans = max(ans, max(lb[i], lr[i]) + max(rb[i], rr[i]));
固然,還要注意答案不能超過原始的長度。htm
拆環爲鏈等細節就不贅述了。token
#include <cstdio> #include <cstring> using namespace std; const int maxn = 710; char s[maxn]; int n,lb[maxn], lr[maxn], rb[maxn], rr[maxn]; inline int max(const int &a, const int &b) { return a > b ? a : b; } int main() { scanf("%d%s", &n, s + 1); memcpy(s + n + 1, s + 1, n); n <<= 1; for (int i = 2; i <= n; ++i) { if (s[i - 1] == 'w') lb[i] = lb[i - 1] + 1, lr[i] = lr[i - 1] + 1; else if (s[i - 1] == 'b') lb[i] = lb[i - 1] + 1, lr[i] = 0; else lb[i] = 0, lr[i] = lr[i - 1] + 1; } for (int i = n - 1; i; --i) { if (s[i] == 'w') rb[i] = rb[i + 1] + 1, rr[i] = rr[i + 1] + 1; else if (s[i] == 'b') rb[i] = rb[i + 1] + 1, rr[i] = 0; else rb[i] = 0, rr[i] = rr[i + 1] + 1; } int ans = 0; for (int i = 1; i <= n; ++i) ans = max(ans, max(lb[i], lr[i]) + max(rb[i], rr[i])); if (ans > n >> 1) ans = n >> 1; printf("%d\n", ans); return 0; }