• Sunscreen


    Sunscreen

    给出n个在x轴上的区间,记第i个区间的左端点和右端点为(l_i,r_i),现在有n种点(显然都是在x轴上),第i种点的坐标都是(p_i),数量有(c_i),每个点只可以标记包含它的一个区间,问最多可以标记多少个区间。(c,lleq 2500)

    注意到这是区间问题,首要考虑排序,而数据范围是给(O(n^2)),选择点时应该会有暴力枚举的过程。

    思路一:

    按左端点排序,然后再来考虑对于一个区间来说选择标记它的点的策略,按照最朴素的思想,显然想选择可以标记这个区间i的点中,坐标最小的点,不妨考虑微扰证明,那么对于后面的区间,对于可以标记区间i的任意两个点(x,y,(x<y))而言,因为后面的区间左端点必然是递增的,显然后面的区间对于它们只有四种情况,一是x可选,y可选,二是x可选,y不可选,三是x不可选,y可选,四是x不可选,y不可选;如果除去第二种情况,那么选择坐标最小的,两者都可选,让i选最小的没问题,后者不可选,自然i必须选前者还是接下来的区间选前者,两者都不可选,自然i选前者选后者都没有关系,但是前者可选,后者不可选,选择前者可能导致后面不优秀,于是此思路萎掉。

    思路二:

    注意到排序方式有两种,而且会造成思路大不同,从这里作为突破点。

    于是按右端点排序,然后接着考虑一个区间i的点的选择的策略情况,参考朴素,想到点的坐标选的尽可能小,此时对于两个点(x,y(x<y))而言,后面的区间j右端点必然是递增的,只需要考虑左端点,判断是否包含这些点,如果左端点(r_j>y),那么x,y对于j都不可选,如果(r_i<xleq r_j),x不可选,y可选,如果(r_ileq x),两者都可选,同思路一的证明方法,容易知道,这三种情况,按照这种朴素贪心都是正确的,再对比一下,容易知道,思路二的情况比思路一少了一种,也就是恶心的x可选,y不可选。

    但是还没完,这只是证明一个区间应该选择那些点,并没有证明,这个区间是否一定要选点,这样考虑,如果这个区间放弃这个点,让别的没有被选的区间选了,答案-1+1,不改变,如果它是让一个已经选的区间选了,腾出来另外一个点给别的区间,答案也是-1-1+1+1,还是没有改变,于是这个区间不选点不会让后面的结果更优,不妨选点。

    到此,题目就结束了,但各位必然深有感触,我们只要排个序,暴力扫描应该选哪一个点,就可以(O(n^2))解决这到题目了,这也照应了开头所讲,会存在暴力枚举选择哪个点的过程。

    区间问题的排序,对于先排左端点还是先排右端点,一定要灵活运用,对于微扰法的证明这样选择结果后面不会更优,一定要全面地考虑所有情况,而且本题存在两个决策,一是一个区间对点的决策,一个是区间的决策,应该思维全面,不要漏掉,这道题很好地考察了贪心的思维。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define il inline
    #define ri register
    #define intmax 0x7fffffff
    using namespace std;
    struct inter{int l,r;
    	il bool operator<(const inter&x)
    		const{return r<x.r;}
    }H[3000],I[3000];
    il void read(int&);
    int main(){
    	int c,l,ans(0);read(c),read(l);
    	for(int i(1);i<=c;++i)read(I[i].l),read(I[i].r);
    	for(int i(1);i<=l;++i)read(H[i].l),read(H[i].r);
    	sort(I+1,I+c+1),H[0].l=intmax;
    	for(int i(1),j,k(0);i<=c;++i){
    		for(j=1;j<=l;++j)
    			if(I[i].l<=H[j].l&&H[j].l<=I[i].r
    			   &&H[j].r&&H[j].l<H[k].l)k=j;
    		if(k)--H[k].r,++ans,k^=k;
    	}printf("%d",ans);
    	return 0;
    }
    il void read(int &x){
    	x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
    	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
    
  • 相关阅读:
    easyui源码翻译1.32--Droppable(放置)
    easyui源码翻译1.32--Draggable(拖动)
    easyui源码翻译1.32--Dialog(对话框窗口)
    easyui源码翻译1.32--DateTimeBox(日期时间输入框)
    easyui源码翻译1.32--DateBox(日期输入框)
    easyui源码翻译1.32--ComboTree(树形下拉框)
    easyui源码翻译1.32--ComboGrid(数据表格下拉框)
    我不曾忘记的初心-大厂小厂
    我不曾忘记的初心-屌丝逆袭
    我不曾忘记的初心-愿天堂没有代码
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11216856.html
Copyright © 2020-2023  润新知