给定一个数组,找出最长的子序列,满足 |
\(\color{Red}{---------------------华丽分割线w(゚Д゚)w------------------------}\)
看到这数据,就觉得暴力无疑。
\(三种情况\)
\(Ⅰ.当x=0,也就是只有中间部分,答案就是出现次数最多的那个数字。\)
\(Ⅱ.当y=0,也就是只有两边的部分,那就要枚举前半部分区间和后半部分区间,设区间为[1,L]和[R,n]\)
\(再枚举a的取值(1-26),答案是区间[1,L]a出现次数和[R,n]a出现次数的较小值\)。
\(Ⅲ.当x和y都不为0,怎么办?其实和2差不多,只不过现在因为y的存在,在区间[L,R]要计算最大的y,也就是出现次数最多的。\)
具体实现,需要维护几个数组降低复杂度,具体看代码。
#include <bits/stdc++.h>
using namespace std;
int t,n,a[2700],L[2009][27],R[2009][27],vis[27];
int main()
{
cin>>t;
while(t--)
{
int da=0;
memset(vis,0,sizeof(vis));
memset(L,0,sizeof(L));
memset(R,0,sizeof(R));
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],vis[a[i]]++;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=26;j++) L[i][j]=L[i-1][j];
L[i][a[i]]++;
}
for(int i=1;i<=26;i++) da=max(da,L[n][i]);
for(int i=n;i>=1;i--)
{
for(int j=1;j<=26;j++) R[i][j]=R[i+1][j];
R[i][a[i]]++;
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
int k=0;
for(int q=1;q<=26;q++)
k=max(k,vis[q]-L[i][q]-R[j][q]);
for(int q=1;q<=26;q++)
da=max(da,k+2*min(L[i][q],R[j][q]));
}
cout<<da<<endl;
}
}