Three Blocks Palindrome (easy version)[暴力-预处理]

给定一个数组,找出最长的子序列,满足
a,a,..a,b,b,..b,a,a,..a
前面的a和后面的a都要是x个,中间的b是y个。
其中,x>=0且y>=0.

\(\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;
	}
}

猜你喜欢

转载自www.cnblogs.com/iss-ue/p/12793432.html
今日推荐