codeforces 1335E2 Three Blocks Palindrome (hard version)

传送门

题意: 给一个串,找子串为三区块回文串的最长可能长度

a i ≤ 200 , ∑ n ≤ 2 e 5 a_i \leq 200, \sum n \leq 2e5 ai200,n2e5

思路: 枚举第一块、第三块和第二块的数字 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;
}

猜你喜欢

转载自blog.csdn.net/qq_39602052/article/details/113178750