Three Blocks Palindrome
E2 - Three Blocks Palindrome (hard version)
参考:Codeforces Round #634 (Div. 3) Editorial
这道题考的主要是前缀和,用sum[i][j]
保存到第 i 个数 j 出现的总次数。
关键代码在这一块,首先遍历两边要取的数字是什么,然后确定两边要取的数字的个数,以便确定边界(l,r)
,然后遍历中间应该取什么数,并且根据 l 和 r 的范围确定该数的个数,最后贪心即可。
for(int mid=1;mid<=200;++mid){
ans=max(ans,int(pos[mid].size()));
for(int side=0; side<pos[mid].size()/2; ++side){
int l=pos[mid][side]+1,r=pos[mid][pos[mid].size()-side-1]-1;
for(int val=1;val<=200;++val){
int sum=sum[r][val]-sum[l-1][val];
ans=max(ans, (side+1)*2+sum);
}
}
}
该题关键点在于,将遍历的重点从 n 转移到了a[i]
的取值范围来,从而将复杂度降低。
// Created by CAD on 2020/4/15.
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int sum[maxn][205];
int a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;cin>>t;
while(t--){
int n;cin>>n;
for(int i=1;i<=n;++i)
cin>>a[i];
vector<int> pos[201];
for(int i=1;i<=n;++i){
for(int j=1;j<=200;++j) sum[i][j]=sum[i-1][j];
sum[i][a[i]]++;
pos[a[i]].push_back(i);
}
int ans=0;
for(int mid=1;mid<=200;++mid){
ans=max(ans,int(pos[mid].size()));
for(int side=0; side<pos[mid].size()/2; ++side){
int l=pos[mid][side]+1,r=pos[mid][pos[mid].size()-side-1]-1;
for(int val=1;val<=200;++val){
int sum=sum[r][val]-sum[l-1][val];
ans=max(ans, (side+1)*2+sum);
}
}
}
cout<<ans<<"\n";
}
return 0;
}
CAD加油!欢迎跟我一起讨论学习算法,QQ:1401650042