Codeforces 1335E2 - Three Blocks Palindrome (贪心)
思路
由于\(a_i\)的取值非常小,所以把每个值所在坐标从小到大存起来。然后枚举每个\(a_i\)为回文的左右边界可得的最大长度。
枚举过程中,求两个\(a_i\)形成的区间中包含的重复次数最多的数。由于区间越大,重复的个数越多,所以从\(a_i\)的最左右两边到中间枚举。
统计区间某个数的重复次数用前缀和。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
#define endl '\n'
#define inf 0x3f3f3f3f
const int M = 998244353;
int arr[N];
int cnt[N][202];
vector<int> pos[202];
int num[202];
int work(int l, int r) {
if(r < l) return 0;
int res = 0;
for(int i = 1; i <= 200; i++) {
res = max(res, cnt[r][i] - cnt[l - 1][i]);
}
return res;
}
int main() {
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t--) {
int n;
cin >> n;
for(int i = 1; i <= 200; i++) pos[i].clear();
for(int i = 0; i <= n; i++) memset(cnt[i], 0, sizeof cnt[i]);
for(int i = 1; i <= n; i++) {
cin >> arr[i];
cnt[i][arr[i]]++;
pos[arr[i]].push_back(i);
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= 200; j++) {
cnt[i][j] += cnt[i - 1][j];
}
}
int ans = 1;
for(int i = 1; i <= 200; i++) {
if(pos[i].size() < 2) continue;
int l = 0, r = pos[i].size() - 1;
while(l <= r) {
ans = max(ans, (l + 1) * 2 - (l == r) + work(pos[i][l] + 1, pos[i][r] - 1));
l++, r--;
}
}
cout << ans << endl;
}
}