E2. Three Blocks Palindrome (hard version) (贪心&暴力)

题目传送门

思路:对于数据较大情况,我们考虑要迅速找到区间 [ l , r ] [l,r] [l,r],显然第一个字符串的数字的个数和第三个字符串个数相同 ,要是区间 [ l , r ] [l,r] [l,r]中数的个数越多,我们只需要让 l l l越靠左, r r r越靠右,而 l , r l,r l,r的确定可以通过记录每个数字对于出现的位置(以空间换时间)。遍历第一个字符串的数字个数,最后取 m a x max max即可。

时间复杂度: O ( 200 × n ) O(200\times n) O(200×n)

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t,n;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		vector<vector<int> >a(201,vector<int>(n+1));
		vector<vector<int> >p(201);//储存每个数的位置. 
		for(int i=1,x;i<=n;i++)
		{
			scanf("%d",&x);
			for(int j=1;j<=200;j++) //前缀和 
				a[j][i]=a[j][i-1]+(x==j);
			p[x].push_back(i);
		}
		int ans=0;
		for(int k=1;k<=200;k++){ //O(n*200*200) 
				ans=max(ans,(int)p[k].size());//如果只取一个子串. 
			for(int i=1;i<=(p[k].size()/2);i++)//左右对称贪心思想. 
			{
				  int l=p[k][i-1]+1,r=p[k][p[k].size()-i]-1;//找到区间[l , r] 
				  for(int j=1;j<=200;j++) //取最大值. 
				  {
				  		int x=a[j][r]-a[j][l-1];
				  		ans=max(ans,i*2+x);
				  }
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}