UVALive 7899 - set维护

解题思路:

首先用两个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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值