题意: 给一个串,找子串为三区块回文串的最长可能长度
a i ≤ 200 , ∑ n ≤ 2 e 5 a_i \leq 200, \sum n \leq 2e5 ai≤200,∑n≤2e5
思路: 枚举第一块、第三块和第二块的数字 x , y x,y x,y,用一个前缀和记录在[l, r]区间内每个字母出现的位置,然后第二块的数字y的个数就可以用区间减得到
不太会算这个方法的复杂度就楞冲了
然后就是剪枝的过程:
先枚举1到200,单个字母更新ans
如果x或y总个数为0则continue,如果xy总个数和小于等于ans 也continue
然后发现n的总和2e5的话,每个数字均摊不会很多,可以用vector存下每个数字的每个位置,然后遍历vector能快很多
双倍经验题xd
事后发现和官方题解差不多xd
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n;
int a[N], pre[N][210];
vector<int> g[210];
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T --) {
for(int i = 0; i < 205; ++i) {
g[i].clear();
}
cin >> n;
for(int i = 1; i <= n; ++i) {
cin >> a[i];
for(int j = 1; j <= 200; ++j) {
pre[i][j] = pre[i - 1][j];
}
pre[i][a[i]] ++;
g[a[i]].push_back(i);
}
int ans = 0;
for(int i = 1; i <= 200; ++i) {
ans = max(ans, pre[n][i]);
}
for(int x = 1; x <= 200; ++x) {
for(int y = 1; y <= 200; ++y) {
if(x == y) continue;
if(pre[n][x] == 0) continue;
if(pre[n][y] == 0) continue;
if(pre[n][x] + pre[n][y] <= ans) continue;
int i = 0, j = g[x].size() - 1;
int cnt = 0;
while(i < j) {
cnt ++;
ans = max(ans, cnt * 2 + pre[g[x][j]][y] - pre[g[x][i]][y]);
++i, --j;
}
}
}
cout << ans << endl;
}
return 0;
}