题目和 C C C 类似,在主数组内,找最长的 1122 1122 1 1 2 2 数组,思路其实都是双指针,但一开始的代码想抽象了
# 错误代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 int n, a[N], maxLen = 0 ;void solve () { cin >> n; for (int i = 1 ; i <= n; i++) cin >> a[i]; vector<int > v; map<int , int > cnt; for (int i = 1 ; i < n; i++) { if (a[i] == a[i + 1 ]) v.push_back (a[i]), i++; else v.push_back (0 ); } for (int i = 0 ; i < v.size (); i++) if (v[i] != 0 ) { cnt.clear (); int l = i, r = i; while (r < v.size () && v[r] != 0 ) { cnt[v[r]]++; while (l < r && cnt[v[r]] == 2 ) cnt[v[l]]--, l++; maxLen = max (maxLen, (r - l + 1 ) * 2 ); r++; } i = r - 1 ; } cout << maxLen << endl; }
# 正确双指针代码注意:题目所要的子串的长度必然是偶数,所以我们找的答案应该是 max(getMax(1), getMax(2))
,同时从 1 1 1 和 2 2 2 两个位置找答案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 int getMax (int idx) { memset (cnt, 0 , sizeof cnt); int l = idx, r = idx, res = 0 ; while (r <= n - 1 ) { if (a[r] != a[r + 1 ]) { while (l < r) cnt[a[l]]--, l++; r += 2 , l += 2 ; } else { cnt[a[r]] += 2 ; while (cnt[a[r]] > 2 ) cnt[a[l]] -= 2 , l += 2 ; r += 2 ; } res = max (res, r - 1 ); } return res; } void solve () { cin >> n; for (int i = 1 ; i <= n; i++) cin >> a[i]; cout << max (getMax (1 ), getMax (2 )) << endl; }
# DP 思路f i f_i f i 存到 i i i 为止的最长子序列长度t i t_i t i 存 i i i 最后 一次出现的位置动态规划时,两个分别表示:
f[i - 1] + 2
表示从 i − 1 i-1 i − 1 这个点到 i + 1 i + 1 i + 1 这个点的最长序列长度i + 1 - t[a[i]]
表示从 i − 1 i - 1 i − 1 这个点到 t a i t_{a_i} t a i 这个点的长度为了保证序列合法,应该在两者之间取 m i n min m i n
1 2 3 4 5 6 7 8 9 10 11 12 void solve () { cin >> n; for (int i = 1 ; i <= n; i++) cin >> a[i]; for (int i = 1 ; i <= n; i++) { if (a[i] == a[i + 1 ]) f[i + 1 ] = min (f[i - 1 ] + 2 , i + 1 - t[a[i]]); t[a[i]] = i; ans = max (ans, f[i + 1 ]); } cout << ans << endl; }
题目传送门
# 错误写法思路和答案类似,都是用的 二分 + 前缀和
来优化处理,但是喜提 A C − 8 , W A − 17 , T L E − 2 \color{green}{AC-8},~\color{red}{WA-17},~\color{brown}{TLE-2} A C − 8 , W A − 1 7 , T L E − 2 错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 int check (int x) { int l = 0 , r = place.size () - 1 ; while (l < r) { int mid = l + r >> 1 ; if (place[mid] < x) l = mid + 1 ; else r = mid; } return l; } void solve () { cin >> n >> q; cin >> s, s = " " + s; for (int i = 1 ; i <= n; i++) { int add1 = (s[i] == '1' ), add2 = (s[i] == '2' ); pre1[i] = pre1[i - 1 ] + add1, pre2[i] = pre2[i - 1 ] + add2; if (s[i] == '/' ) place.push_back (i); } while (q--) { int l, r; cin >> l >> r; int beginIdx = check (l), ans = 1 ; if (place.size () == 0 || place[beginIdx] < l ) { cout << 0 << endl; continue ; } for (int i = beginIdx; i < place.size () && place[i] <= r; i++) { int t = place[i]; if (t >= 2 ) { int left1 = pre1[t] - pre1[l - 1 ], right2 = pre2[r] - pre2[t]; ans = max (ans, max ((int )0 , min (left1, right2)) * 2 + 1 ); } } cout << ans << endl; } }
# 正解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void solve () { cin >> n >> Q >> s; s = ' ' + s; for (int i = 1 ; i <= n; i++) { if (s[i] == '/' ) a[++m] = i; s1[i] = s1[i - 1 ] + (s[i] == '1' ); s2[i] = s2[i - 1 ] + (s[i] == '2' ); } while (Q--) { cin >> L >> R; int l = 1 , r = m, ans = 0 ; while (l <= r) { int mid = l + (r - l) / 2 ; if (a[mid] < L) l = mid + 1 ; else if (a[mid] > R) r = mid - 1 ; else { int c1 = s1[a[mid]] - s1[L - 1 ], c2 = s2[R] - s2[a[mid] - 1 ]; ans = max (ans, min (c1, c2) * 2 + 1 ); if (c1 <= c2) l = mid + 1 ; else r = mid - 1 ; } } cout << ans << "\n" ; } }