HDU 6003 Problem Buyer

贪心题(好久不做了)

题解

考虑最一般的,判断合法性?

经典贪心问题:左端点升序,左端点相同,右端点降序,c[i]升序

优先队列,每次选择覆盖x的右端点最小的区间。

称此方法为“区间匹配贪心”

 

最小的k使得任意选k个都能存在“完美匹配”?(虽然这里不用Hall定理)

对于覆盖了ci的区间设有ti个,那么ans至少是n-ti+1

一个naive的想法是,ans就是max(n-ti+1)??

 

但是可能不止这样,因为存在共用区间的问题

所以边找ti,边进行之前的贪心匹配。

这样,到了i,用n-q.size()+1进行更新ans,然后q.pop(),表示用右端点最小的区间匹配上c[i]

当queue是空的,显然impossible

 

考虑有解情况,合法性:

证明两点:

1.这样的ans是下界。首先“区间匹配贪心”这样分配是最优的。枚举x相当于最后满足的是哪个,剩下的都选择上。即使有一个可能覆盖了c[i],但是钦定匹配给了别人,

由于“区间匹配贪心”正确,所以换到c[i]一定不优。这一定是下界。

2.只要证明存在合法的分配方式,就可以证明ans也是上界。对于一个c[i],虽然可能给了一个ti的区间可能被钦定给了c[i+j]的,但是这样会在c[i+j]的位置统计到。

由于是取max,所以一定会考虑到!!

否则显然存在构造方法。

所以ans也是下界。

证毕。

 

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}
namespace Modulo{
const int mod=998244353;
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
void inc(int &x,int y){x=ad(x,y);}
int mul(int x,int y){return (ll)x*y%mod;}
void inc2(int &x,int y){x=mul(x,y);}
int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
template<class ...Args>il int ad(const int a,const int b,const Args &...args) {return ad(ad(a,b),args...);}
template<class ...Args>il int mul(const int a,const int b,const Args &...args) {return mul(mul(a,b),args...);}
}
// using namespace Modulo;
namespace Miracle{
const int N=1e5+5;
int n,m;
int ans;
int c[N];
priority_queue<int,vector<int>,greater<int> >q;
struct seg{
    int l,r;
    bool friend operator <(seg a,seg b){
        if(a.l==b.l) return a.r>b.r;
        return a.l<b.l;
    }
}s[N];
void clear(){
    while(!q.empty()) q.pop();
}
int main(){
    int t;rd(t);
    for(reg o=1;o<=t;++o){
        clear();
        rd(n);rd(m);
        for(reg i=1;i<=n;++i){
            rd(s[i].l);rd(s[i].r);
        }
        sort(s+1,s+n+1);
        for(reg i=1;i<=m;++i){
            rd(c[i]);
        }
        sort(c+1,c+m+1);
        int ptr=0;
        int ans=0;
        for(reg i=1;i<=m;++i){
            while(ptr<n&&s[ptr+1].l<=c[i]){
                if(s[ptr+1].r>=c[i]) q.push(s[ptr+1].r);
                ++ptr;
            }
            while(!q.empty()&&q.top()<c[i]) q.pop();
            if(q.empty()) {
                ans=-1;break;
            }
            ans=max(ans,n-(int)q.size()+1);
            q.pop();
        }
        if(ans>=0) printf("Case #%d: %d\n",o,ans);
        else printf("Case #%d: IMPOSSIBLE!\n",o);
    }    
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/

鸽巢原理,但是可能不存在合法方案,就现场匹配。

为了保证最优性,利用“区间匹配贪心”

posted @ 2019-06-10 21:46  *Miracle*  阅读(237)  评论(0编辑  收藏  举报