Gym 101194C / UVALive 7899 - Mr. Panda and Strips - [set][2016 EC-Final Problem C]

題目連接:php

http://codeforces.com/gym/101194/attachmentsc++

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5921spa

 

題意:.net

一個長度爲 $N$ 的序列,要求選出兩段不重疊的區間,要求兩個區間包含的元素均互不相同,求兩段區間的長度和最大爲多少。code

 

題解:blog

(主要參考https://blog.csdn.net/a1214034447/article/details/78768645ci

首先用 $back[i]$ 和 $front[i]$ 分別表示 $i$ 這個位置的數從i往右看第一次出現的位置,和往左看第一次出現的位置。get

接着,咱們從位置 $n$ 開始倒退回去枚舉右區間的左端點 $r$,用 $rlen = back[r] - r$ 表示當前位置往右延伸的最長長度,而且用一個set保存目前右區間 $[r,back[r])$ 裏全部的數。it

而後,對於每一個 $r$,均枚舉左區間的右端點 $l(l<r)$,用 $llen = l - front[l]$ 表示目前該位置往左延伸的最長長度。io

同時,再用一個set維護:找到左區間裏,全部在右區間出現過的數,存儲這些數的下標。

接下來依次枚舉這些數,考慮這些數若不讓其在右區間取到(固然,還有一種狀況是都在右區間取),那麼能夠算出此時相應左區間最長能有多長。將左右區間長度求和,維護最大值。

 

AC代碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
const int maxc=1e5+10;

int n,m;
int num[maxn],pos[maxc];
int bak[maxn],frt[maxn];
set<int> st,se;

inline int maxllen(int p,int l,int llen)
{
    auto it=se.end();
    while((it--)!=se.begin())
        if(pos[num[*it]]<p) return l-(*it);
    return llen;
}

int main()
{
    int T;
    cin>>T;
    for(int kase=1;kase<=T;kase++)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&num[i]);

        memset(pos,0,sizeof(pos));
        for(int i=1;i<=n;i++)
        {
            frt[i]=pos[num[i]];
            pos[num[i]]=i;
        }
        memset(pos,0x3f3f3f3f,sizeof(pos));
        for(int i=n;i>=1;i--)
        {
            bak[i]=pos[num[i]];
            pos[num[i]]=i;
        }

        int ans=1;
        st.clear();
        for(int i=n,rlen=1;i>=1;i--,rlen++)
        {
            while(bak[i] <= i+rlen-1)
            {
                st.erase(num[i+rlen-1]);
                rlen--;
            }
            st.insert(num[i]), pos[num[i]]=i;
            se.clear();
            for(int j=1,llen=1;j<i;j++,llen++)
            {
                while(frt[j] >= j-llen+1)
                {
                    se.erase(j-llen+1);
                    llen--;
                }
                if(st.count(num[j])) se.insert(j);
                if(!se.size()) ans=max(ans,llen+rlen);
                else ans=max(ans,j-*(--se.end())+rlen);
                for(auto it=se.begin();it!=se.end();it++)
                    ans=max(ans,maxllen(pos[num[*it]],j,llen)+pos[num[*it]]-i);
            }
        }
        printf("Case #%d: %d\n",kase,ans);
    }
}
相關文章
相關標籤/搜索