解题思路:
首先用两个back和front数组分别表示i这个位置的数从i往右看第一次出现的位置,和往左看第一次出现的位置。然后我们从n开始倒退回去枚举表示r这个位置往右延伸得到最长的长度len,并且用set保存长度之中的数。另外我们判断的就是另一个区间从l位置(l<r)往左延伸的最长长度lon,并且再用一个set维护左区间和右区间内相同的数,那么接下来的事情就是考虑这些数在r区间不取的情况,在l区间取的情况得到的最大值就是了。
#include<bits/stdc++.h>
#define lson l,mid
#define rson mid+1,r
using namespace std;
typedef long long ll;
int n,m;
const int mx = 1e3+10;
int num[mx],back[mx],po[mx*100],front[mx];
set<int> st,se;
int pos_val(int pos,int lon)
{
auto ip = se.end();
while((ip--)!=se.begin()){
if(po[num[*ip]]<pos)
return *ip;
}
return lon;
}
int main()
{
int t,cas = 1;
freopen("1in","r",stdin);
scanf("%d",&t);
while(t--){
scanf("%d",&n);
st.clear();
memset(po,0,sizeof(po));
for(int i=1;i<=n;i++){
scanf("%d",num+i);
front[i] = po[num[i]];
po[num[i]] = i;
}
for(int i=1;i<=100*mx;i++) po[i] = n+1;
for(int i=n;i>=1;i--){
back[i] = po[num[i]];
po[num[i]] = i;
}
int ans = 1,len = 0;//ans最小肯定是1
for(int i=n;i>=1;i--){
while(back[i]<=i+len) st.erase(num[i+(len--)]);
st.insert(num[i]), po[num[i]] =i;
se.clear(), len++;
for(int j=1,lon=0;j<i;j++){
while(front[j]>=j-lon) se.erase(j-(lon--));
lon++;
if(st.count(num[j])) se.insert(j);
if(!se.size()) ans = max(ans,lon+len);
else ans = max(ans,len+j-*(--se.end()));
for(auto it=se.begin();it!=se.end();it++)
ans = max(ans,po[num[*it]]-i+j-pos_val(po[num[*it]],j-lon));
}
}
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}