LINK

预处理 f [ i ] [ j ] f[i][j] f[i][j]表示 [ i , j ] [i,j] [i,j]能取到的最长区间

枚举第一个区间的左端点,往右一直尺取

一旦发现有颜色出现两次跳出循环

否则加入一个新颜色,把数组的这些颜色位置都标记一下代表第二个段不能选

那么第二个段只能选连续 0 0 0

我们可以 O ( n ) O(n) O(n)扫描一编,可以得到若干个极长的 0 0 0

f f f数组我们就可以知道第二段的最大长度

最坏复杂度 O ( n 3 ) O(n^3) O(n3),不过剪枝比较多,实际上还跑的很快

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+10;
int n,t,a[maxn],li[maxn];
int f[maxn][maxn],vis[maxn],r[maxn],casenum,top;
vector<int>vec[maxn];
void read()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)	scanf("%d",&a[i]),li[i] = a[i];
	sort( li+1,li+1+n );
	top = unique(li+1,li+1+n)-li-1;
	for(int i=1;i<=n;i++)	a[i] = lower_bound(li+1,li+1+top,a[i])-li;	
}
void initF()
{
	memset( f,0,sizeof f );
	for(int i=1;i<=n;i++)
	{
		memset( vis,0,sizeof vis );
		for(int j=i;j<=n;j++)
		{
			if( vis[a[j]] )	break;
			vis[a[j]] = 1, f[i][j] = j-i+1;
		}
	}
	for(int l=2;l<=n;l++)
	for(int i=1,j=i+l-1;j<=n;i++,j++)
		f[i][j] = max( f[i][j],max(f[i+1][j],f[i][j-1]) );
}
int main()
{
	int t; cin >> t;
	while( t-- )
	{
		read();	
		for(int i=1;i<=n;i++)	vec[a[i]].push_back( i );
		initF();
		int ans = 0;
		for(int i=1;i<=n;i++)
		{
			if( n-i+1<=ans )	break;
			memset( vis,0,sizeof vis );
			memset( r,0,sizeof r );
			for(int j=i;j<=n;j++)
			{
				if( vis[a[j]] )	break;
				vis[a[j]] = 1;
				for( auto v:vec[a[j]] )	r[v] = 1;//标记为不可选择
				int now = 0, l = j+1;
				for(int q=j+1;q<=n;q++)
				{
					if( !r[q] )	now = max( now,f[l][q] );
					else	l = q+1;
				} 
				ans = max( ans,j-i+1+now );
			}
		}
		printf("Case #%d: %d\n",++casenum,ans);
		memset( vis,0,sizeof vis ); memset( r,0,sizeof r );
		for(int i=1;i<=n;i++)	vec[i].clear();
	}
}