zoukankan      html  css  js  c++  java
  • Gym 101194C / UVALive 7899

    题目链接:

    http://codeforces.com/gym/101194/attachments

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

    题意:

    一个长度为 $N$ 的序列,要求选出两段不重叠的区间,要求两个区间包含的元素均互不相同,求两段区间的长度和最大为多少。

    题解:

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

    首先用 $back[i]$ 和 $front[i]$ 分别表示 $i$ 这个位置的数从i往右看第一次出现的位置,和往左看第一次出现的位置。

    接着,我们从位置 $n$ 开始倒退回去枚举右区间的左端点 $r$,用 $rlen = back[r] - r$ 表示当前位置往右延伸的最长长度,并且用一个set保存目前右区间 $[r,back[r])$ 里所有的数。

    然后,对于每个 $r$,均枚举左区间的右端点 $l(l<r)$,用 $llen = l - front[l]$ 表示目前该位置往左延伸的最长长度。

    同时,再用一个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
    ",kase,ans);
        }
    }
  • 相关阅读:
    nginx日志格式字段
    set_include_path和get_include_path用法详解
    nginx try_files 详解
    ul ol li的序号编号样式
    PHP中报500错误时如何查看错误信息
    nginx的access.log文件详解
    一些常用服务命令和配置目录
    PHP 使用 Redis
    HTML5-indexedDB使用常见错误总结
    浏览器数据库 IndexedDB 入门
  • 原文地址:https://www.cnblogs.com/dilthey/p/9902050.html
Copyright © 2011-2022 走看看