zoukankan      html  css  js  c++  java
  • bzoj2811[Apio2012]Guard 贪心

    2811: [Apio2012]Guard

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 905  Solved: 387
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    5 3 4
    1 2 1
    3 4 1
    4 4 0
    4 5 1

    Sample Output

    3
    5

    HINT

    在这个样例中,有两种可能的安排方式:1,3,5 或者 2,3,5。即 3 和 5
    后面必然躲着一个忍者。
    考虑第一个灌木丛,存在一种安排方案使得它的后面躲着忍者,但也存在一
    种安排方案使得它后面没有躲忍者,因此不应该输出 1。同理,不应该输出 2。

     

    贪心。
    把所有不可能出现忍者的位置除去,重新编号序列  可以用差分实现
    对区间进行操作,对于可能存在忍者的区间,把它缩小到没有不可能出现忍者的位置,并去除包含关系
    这样,剩下的区间就只能是l递增,r递增的了
    对于每个剩下的区间,我们都要选一个区间内的点,根据贪心来说,选右端点最优
    因为在几个区间重复的部分选一点可以使这几个区间都被处理,右端点最可能被几个区间包含

    因此我们得到贪心策略:
    对于每一个有效区间,选择右端点可以使满足每个区间的要求(当然有些区间包含之前选择的右端点就不选了),并让已知位置的忍者数最少


    但是每个区间我们不一定要选择r点,还可能选择r-1,r-2,r-3...这些点来使得区间满足
    现在我们要判断的是对于某一个区间,我们是否能唯一选择r点必定出现忍者

    我们假设在r-1放一个忍者来满足当前区间且在r不放忍者,如果确实可以满足那么r点不一定会出现忍者
    预处理出f[i],g[i]表示从前向后,从后向前选择点使得 到i的前缀,后缀区间都满足
    设r-1不能满足的向前数第一个区间为t1,向后数第一个区间为t2   那么r-1不可行的条件就是f[t1]+g[t2]+1>K

    至于为什么要选择r-1来判断r可行, 是因为r-1更有可能被更多的区间包含,让r不一定出现忍者的期望更大

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #define ll long long
    #define N 100050
    using namespace std;
    int n,m,k,cnt,val[N],f[N],g[N],cf[N],ql[N],qr[N];
    struct query{int l,r,c;}q[N];
    vector<pair<int,int> >p;
    int main(){
        scanf("%d%d%d",&n,&k,&m);
        
        //重新构造序列 
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].c);
            if(!q[i].c)cf[q[i].l]++,cf[q[i].r+1]--;
        }
        int now=0;
        for(int i=1;i<=n;i++){
            now+=cf[i];
            if(now<=0)ql[i]=qr[i]=++cnt,val[cnt]=i;
        }
        if(cnt==k){
            for(int i=1;i<=cnt;i++)printf("%d
    ",val[i]);
            return 0;
        }
        for(int i=1;i<=n;i++)if(!qr[i])qr[i]=qr[i-1];
        ql[n+1]=n+1;
        for(int i=n;i;i--)if(!ql[i])ql[i]=ql[i+1];
        for(int i=1;i<=m;i++){
            if(!q[i].c)continue;
            int l=q[i].l,r=q[i].r;
            l=ql[l];r=qr[r];
            if(l>r)continue;
            p.push_back(make_pair(l,r));
        }
        sort(p.begin(),p.end());
        int tp=0,fg=0;
        for(int i=0;i<p.size();i++){
            while(tp&&p[i].first>=ql[tp]&&p[i].second<=qr[tp])tp--;
            ql[++tp]=p[i].first;qr[tp]=p[i].second;
        }
        //重新构造序列 
        
        int R=0,L=n+1;
        for(int i=1;i<=tp;i++){
            if(ql[i]>R)f[i]=f[i-1]+1,R=qr[i];
            else f[i]=f[i-1];
        }
        for(int i=tp;i;i--){
            if(qr[i]<L)g[i]=g[i+1]+1,L=ql[i];
            else g[i]=g[i+1];
        }
        for(int i=1;i<=tp;i++){
            if(f[i]==f[i-1])continue;
            if(ql[i]==qr[i]){
                printf("%d
    ",val[ql[i]]);
                fg=1;continue;
            }
            int x=qr[i]-1,l=1,r=i-1,t1=0,t2=tp+1;
            while(l<=r){
                int mid=l+r>>1;
                if(qr[mid]<x)t1=mid,l=mid+1;
                else r=mid-1;
            }
            l=i+1;r=tp;
            while(l<=r){
                int mid=l+r>>1;
                if(ql[mid]>x)t2=mid,r=mid-1;
                else l=mid+1;
            }
            if(f[t1]+g[t2]+1>k){
                printf("%d
    ",val[qr[i]]);
                fg=1;
            }
        }
        if(!fg)puts("-1");
        return 0;
    }

  • 相关阅读:
    DB2 for Z/os Statement prepare
    Foreign key (referential) constraints on DB2 LUW v105
    复制Informational constraints on LUW DB2 v105
    DB2 SQL Mixed data in character strings
    DB2 create partitioned table
    MVC中使用EF的技巧集(一)
    Asp.Net MVC 开发技巧(二)
    Linq使用技巧及查询示例(一)
    Asp.Net MVC 开发技巧(一)
    Asp.Net MVC Identity 2.2.1 使用技巧(八)
  • 原文地址:https://www.cnblogs.com/wsy01/p/8074534.html
Copyright © 2011-2022 走看看