(CF1335E)Three Blocks Palindrome

原题链接 (Hard Version)

思路:

设数组 \(sum(c,r)\) 表示数字 \(c\) 在区间 \([1,r]\) 的个数,数组 \(cnt(c,k)\) 表示第 \(k\) \(c\) 的位置.

经过分析可知,若第一个区间 (和第三个区间) 有 \(k\) 个数字 \(a\), 若要使区间最长,这 \(k\) 个数字是最左边 (和最右边) 的 \(k\) \(a\).

假设第一个区间 (和第三个区间) 为 \(k\) 个数字 \(a\), 则第二个区间的左端点 \(l=cnt(a,k)+1\), 右端点 \(r=cnt(a,sum(a,n)-k+1)-1\), 则第二个区间长度的最大值为 \(m = \max\limits_{c=1}^{200} \{ sum(c,r)-sum(c,l-1) \}\), 序列总长度为 \(2k + m\).

枚举 \(k\) 与数字 \(a\) 即可得到最大长度,时间复杂度 \(O(an)\)(\(a\) 为原数组 \(a_i\) 的最大值), 空间复杂度 \(O(an+n)\).

原先写了个 O (an^2) 的代码交 easy ver. 结果被 hack 了 QAQ

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <cstring>
#include <cstdio>
#include <vector>
using std::vector;
const int Mn(200500),Ma(205);
int sum[Mn][Ma];
vector<int> cnt[Ma];

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(vector<int>& a:cnt) //注意初始化
a.clear();
int mxa(0); //ai的最大值
for(int i(1);i<=n;++i)
{
int a;
scanf("%d",&a);
memcpy(sum[i],sum[i-1],sizeof sum[i]);
++sum[i][a];
cnt[a].push_back(i);
if(mxa<a) mxa = a;
}
int ans(1);
for(int i(1);i<=mxa;++i)
{
int jmx = cnt[i].size()/2; //枚举量j的最大值
for(int j(1);j<=jmx;++j) //从1开始枚举不失一般性
{
int l(cnt[i][j-1]+1),r(cnt[i][cnt[i].size()-j]-1);
for(int k(1);k<=mxa;++k)
ans = ans<(2*j+sum[r][k]-sum[l-1][k]) ? (2*j+sum[r][k]-sum[l-1][k]) : ans;
}
}
printf("%d\n",ans);
}
return 0;
}