zoukankan      html  css  js  c++  java
  • 【CF392D】Three Arrays-set+multiset

    测试地址:Three Arrays
    题目大意:有三个长为n的数列A,B,C,要求从A中取前a个数,从B中取前b个数,从C中取前c个数,使得取出的数的并集和这三个数列的并集相等,求最小的a+b+c
    做法:本题需要用到set+multiset。
    这题也是清北学堂讲的,思想非常不错,写在这里跟大家分享。
    考虑只有两个数列怎么做,先预处理出fa(i),fb(i),表示iAB中最早出现的位置。我们可以从大到小枚举aa越小,对b的限制越多,每个限制都形如bfb(i)这种形式,这样我们可以O(n)求出。
    那么现在有三个数列,我们又要怎么做呢?也是考虑从大到小枚举aa越小,对b,c的限制越多,每个限制都形如:bfb(i)cfc(i)。以b,c为横纵坐标建平面直角坐标系,将限制映射到坐标系上,我们发现这其实就是将点(fb(i),fc(i))左下的区域全部挖去。那么此时我们怎么找最小的b+c呢?观察发现,我们挖掉不能取的那些区域后,剩下的区域有很多向左下凸出来的拐角,那么最小的b+c必定在这些拐角中的一个取得。所以我们现在的目标就是维护这个阶梯形状的东西。
    考虑维护组成阶梯形的那些限制。随着a的变小,对b,c的限制不断增多,也就是不断挖掉新的区域,有时我们会发现新的区域包含了一些旧的区域,这时候旧的区域就没有必要存下来了,我们就删除这个限制。又因为一个区域最多加入一次、删除一次,一共有不超过3n个区域,用set维护的话,就可以做到O(nlogn)的复杂度了。同时再用一个multiset来维护拐角上b+c的所有可能取值即可。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int inf=1000000000;
    int n,a[100010],b[100010],c[100010],tot;
    int fa[300010]={0},fb[300010]={0},fc[300010]={0};
    struct forsort
    {
        int val,id1,id2;
    }f[300010];
    struct Pair
    {
        int b,c;
    };
    bool operator < (Pair a,Pair b) {return a.b<b.b;}
    set<Pair> s;
    set<Pair>::iterator it;
    multiset<int> vals;
    multiset<int>::iterator valit;
    
    bool cmp(forsort a,forsort b)
    {
        return a.val<b.val;
    }
    
    void init()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&f[++tot].val);
            f[tot].id1=1,f[tot].id2=i;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&f[++tot].val);
            f[tot].id1=2,f[tot].id2=i;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&f[++tot].val);
            f[tot].id1=3,f[tot].id2=i;
        }
    
        sort(f+1,f+3*n+1,cmp);
        tot=0;
        for(int i=1;i<=3*n;i++)
        {
            if (i==1||f[i].val!=f[i-1].val) tot++;
            if (f[i].id1==1) a[f[i].id2]=tot;
            if (f[i].id1==2) b[f[i].id2]=tot;
            if (f[i].id1==3) c[f[i].id2]=tot;
        }
    
        for(int i=1;i<=n;i++)
            if (!fa[a[i]]) fa[a[i]]=i;
        for(int i=1;i<=n;i++)
            if (!fb[b[i]]) fb[b[i]]=i;
        for(int i=1;i<=n;i++)
            if (!fc[c[i]]) fc[c[i]]=i;
    }
    
    void insertPair(int newb,int newc)
    {
        int nowb,nowc;
        Pair e={newb,newc};
        it=s.upper_bound(e);
        if ((*it).c>=e.c) return;
        nowc=(*it).c;
        it--;
        valit=vals.find((*it).b+nowc);
        vals.erase(valit);
        while((*it).c<=e.c)
        {
            nowb=(*it).b,nowc=(*it).c;
            it--;
            vals.erase((*it).b+nowc);
            it++;
            s.erase(it);
            it=s.lower_bound(e);
            it--;
        }
        nowb=(*it).b,nowc=(*it).c;
        vals.insert(nowb+e.c);
        it++;
        nowc=(*it).c;
        vals.insert(e.b+nowc);
        s.insert(e);
    }
    
    void work()
    {
        Pair e;
        e.b=0,e.c=inf+1;
        s.insert(e);
        e.b=inf+1,e.c=0;
        s.insert(e);
        vals.insert(0);
        for(int i=1;i<=tot;i++)
            if (!fa[i]) insertPair(fb[i]?fb[i]:inf,fc[i]?fc[i]:inf);
        int ans=inf;
        bool flag=1;
        for(int i=n;i>=1;i--)
        {
            ans=min(ans,i+(*vals.begin()));
            if (fa[a[i]]==i)
            {
                if (!fb[a[i]]&&!fc[a[i]]) {flag=0;break;}
                insertPair(fb[a[i]]?fb[a[i]]:inf,fc[a[i]]?fc[a[i]]:inf);
            }
        }
        if (flag) ans=min(ans,(*vals.begin()));
        printf("%d",ans);
    }
    
    int main()
    {
        init();
        work();
    
        return 0;
    }
  • 相关阅读:
    php实现简单的流程管理
    【百度地图API】如何制作多途经点的线路导航——驾车篇
    利用MFC实现浏览器的定制与扩展(JavaScript与C++交互)
    c++与js脚本交互,C++调用JS函数/JS调用C++函数
    VC/MFC中通过CWebPage类调用javascript函数(给js函数传参,并取得返回值)
    Android中半透明Activity效果另法
    mac java环境
    在Mac osx使用ADT Bundle踩过的坑
    Android自动检测版本及自动升级
    C++编译遇到参数错误(cannot convert parameter * from 'const char [**]' to 'LPCWSTR')
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793465.html
Copyright © 2011-2022 走看看