zoukankan      html  css  js  c++  java
  • 【BZOJ-1178】CONVENTION会议中心 倍增 + set (神思路好题!)

    1178: [Apio2009]CONVENTION会议中心

    Time Limit: 15 Sec  Memory Limit: 162 MB
    Submit: 812  Solved: 323
    [Submit][Status][Discuss]

    Description

    Siruseri政府建造了一座新的会议中心。许多公司对租借会议中心的会堂很感兴趣,他们希望能够在里面举行会议。 对于一个客户而言,仅当在开会时能够独自占用整个会堂,他才会租借会堂。会议中心的销售主管认为:最好的策略应该是将会堂租借给尽可能多的客户。显然,有可能存在不止一种满足要求的策略。 例如下面的例子。总共有4个公司。他们对租借会堂发出了请求,并提出了他们所需占用会堂的起止日期(如下表所示)。 开始日期 结束日期 公司1 4 9 公司2 9 11 公司3 13 19 公司4 10 17 上例中,最多将会堂租借给两家公司。租借策略分别是租给公司1和公司3,或是公司2和公司3,也可以是公司1和公司4。注意会议中心一天最多租借给一个公司,所以公司1和公司2不能同时租借会议中心,因为他们在第九天重合了。 销售主管为了公平起见,决定按照如下的程序来确定选择何种租借策略:首先,将租借给客户数量最多的策略作为候选,将所有的公司按照他们发出请求的顺序编号。对于候选策略,将策略中的每家公司的编号按升序排列。最后,选出其中字典序最小1的候选策略作为最终的策略。 例中,会堂最终将被租借给公司1和公司3:3个候选策略是{(1,3),(2,3),(1,4)}。而在字典序中(1,3)<(1,4)<(2,3)。 你的任务是帮助销售主管确定应该将会堂租借给哪些公司。

    Input

    输入的第一行有一个整数N,表示发出租借会堂申请的公司的个数。第2到第N+1行每行有2个整数。第i+1行的整数表示第i家公司申请租借的起始和终止日期。对于每个公司的申请,起始日期为不小于1的整数,终止日期为不大于10^9的整数。N≤200000

    Output

    输出的第一行应有一个整数M,表示最多可以租借给多少家公司。第二行应列出M个数,表示最终将会堂租借给哪些公司。

    Sample Input

    4
    4 9
    9 11
    13 19
    10 17

    Sample Output

    2
    1 3

    HINT

    修复数据bug,并新加数据一组By NanoApe 2016.5.11

    修复后数据:JudgeOnline/upload/201605/dd.rar

    Source

    Solution

    思路非常神

    首先我们如果只要求数目最多,显然可以贪心,即线段覆盖

    字典序最小就很麻烦了

    方法还是贪心,按照读入的顺序,判断,如果使当前满足,能够达到最优,那么就选当前

    问题是如何加速判断的过程

    $f[i][j]$表示,以$i$时间开始,选$2^{j}$条线段后,右端点最近在哪

    这个信息显然是可以合并的,那么倍增解决

    判断的时候,用数据结构维护一下就可以,比如用set查询前驱后继

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<set>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0';  ch=getchar();}
        return x*f;
    }
    #define MAXN 200010
    #define INF 0x3f3f3f3f
    int N;
    struct CompanyNode{int s,t,id;}c[MAXN],tmp[MAXN],b[MAXN];
    bool cmp1(CompanyNode A,CompanyNode B) {return A.s==B.s? A.t>B.t : A.s<B.s;}
    bool cmp2(CompanyNode A,CompanyNode B) {return A.id<B.id;}
    struct SetNode
    {
        int x,f;
        SetNode (int x,int f) : x(x),f(f) {}
        bool operator < (const SetNode & A) const
            {return x<A.x;}
    };
    set<SetNode>st;
    set<SetNode>::iterator lst,rst;
    int f[MAXN<<1][20];
    int Cal(int l,int r)
    {
        int re=0;
        for (int i=17; i>=0; i--)
            if (f[l][i]<=r) l=f[l][i]+1,re+=1<<i;  //一定要+1
        return re;
    }
    int ls[MAXN<<1],tp,top;
    int main()
    {
        //freopen("data.in","r",stdin); freopen("data.out","w",stdout);
        N=read();
        for (int i=1; i<=N; i++) ls[++tp]=c[i].s=read(),ls[++tp]=c[i].t=read(),c[i].id=i;
        sort(ls+1,ls+tp+1);
        top=unique(ls+1,ls+tp+1)-ls-1;
        for (int i=1; i<=N; i++) 
            c[i].s=lower_bound(ls+1,ls+top+1,c[i].s)-ls,c[i].t=lower_bound(ls+1,ls+top+1,c[i].t)-ls;
        sort(c+1,c+N+1,cmp1);
        int last=INF; tp=0;
        for (int i=N; i>=1; i--) if (c[i].t<last) tmp[++tp]=c[i],last=c[i].t;
        reverse(tmp+1,tmp+tp+1);
    //    for (int i=1; i<=tp; i++) printf("%d %d %d
    ",tmp[i].s,tmp[i].t,tmp[i].id);
        memset(f,0x3f,sizeof(f));
    //    printf("%d %d
    ",f[1],INF);
        for (int i=top,j=tp; i>=1; i--)
            {
                f[i][0]=f[i+1][0];
                if (tmp[j].s==i) f[i][0]=min(f[i][0],tmp[j].t); 
                for (int k=1; k<=17; k++)
                    if (f[i][k-1]!=INF)
                        f[i][k]=f[f[i][k-1]+1][k-1];
                while (tmp[j].s==i) j--;
            }
    //    for (int i=1; i<=N; i++) printf("%d %d %d
    ",c[i].id,c[i].s,c[i].t);
        printf("%d
    ",Cal(1,top));
        sort(c+1,c+N+1,cmp2);
        st.insert(SetNode(0,-1)); st.insert(SetNode(top+1,1));
        int cnt=0;
        for (int i=1; i<=N; i++)
            {
                SetNode ls=SetNode(c[i].s,1),rs=SetNode(c[i].t,-1);
                lst=st.lower_bound(ls); rst=st.upper_bound(rs);
                if (lst!=rst || (*rst).f==-1) continue;
                lst--;
                int L=(*lst).x+1,R=(*rst).x-1;
                if (Cal(L,c[i].s-1)+Cal(c[i].t+1,R)+1==Cal(L,R))
                    {
                        st.insert(ls),st.insert(rs);
                        cnt++; if (cnt==1) printf("%d",c[i].id); else printf(" %d",c[i].id);
                    }
            }
        puts("");
        return 0;
    }
  • 相关阅读:
    zoj 3627#模拟#枚举
    Codeforces 432D Prefixes and Suffixes kmp
    hdu 4778 Gems Fight! 状压dp
    CodeForces 379D 暴力 枚举
    HDU 4022 stl multiset
    手动转一下田神的2048
    【ZOJ】3785 What day is that day? ——KMP 暴力打表找规律
    poj 3254 状压dp
    C++中运算符的优先级
    内存中的数据对齐
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5800744.html
Copyright © 2011-2022 走看看