贪心题(好久不做了)
考虑最一般的,判断合法性?
经典贪心问题:左端点升序,左端点相同,右端点降序,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(' ');} 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 ",o,ans); else printf("Case #%d: IMPOSSIBLE! ",o); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* */
鸽巢原理,但是可能不存在合法方案,就现场匹配。
为了保证最优性,利用“区间匹配贪心”