【 贪心 进阶总结 】【 来自一本通提高篇 】

#10000. 「一本通 1.1 例 1」活动安排

区间与区间的最大不覆盖数—套板子(区间右端点从小到大排序,选择不冲突的,尽可能的选)简记为线段覆盖问题

#10001. 「一本通 1.1 例 2」种树

区间内最少单点满足覆盖要求,不管是各个区间需要一个点还是一个子区间(这个子区间是可连续、可不连续的)

按照区间右端点从小到大排序,依次满足各个区间的要求,如此下来种的树(需要的点)最少。

如果想不出贪心,线段树+优化亦可作。

#10002. 「一本通 1.1 例 3」喷水装置

选择尽量少的区间覆盖指定线段区间。

【 模板 】将所有的区间按照左端点从小到大排序,对于当前查找的起点s ,选择覆盖点 s 的区间中右端点中最大的一个,并将 s 更新为此区间的右端点,(这样区间数目+1)直到s>=整个线段长度。(在s时刻,找一个左端点小于等于s的最大右端点)

对于这道题,需要进行一些转化——每个浇灌喷头受限于所能喷到的最短距离,它的最短距离是半径到达草坪上端。此时,如果将整个草坪长度想象为 x轴的正半轴,那么,我们应该根据勾股定理找到水平距离,即(\sqrt{r^{2}-(\frac{W}{2})^{2}})。把当前点的pos减去水平距离作为左端点,pos+水平距离作为右端点。然后就是套上面的板子↑。

PS:一定要理解了过程再写,一定要理解了过程再写,一定要理解了过程再写!!!

附上AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 300005

using namespace std;

const double Eps = 1e-5 ;

inline int wread(){
    char c=getchar ();int flag=1,wans=0;
    while (c<'0'||c>'9'){if (c=='-') flag=-1;c=getchar ();}
    while (c>='0'&&c<='9'){wans=wans*10+c-'0';c=getchar ();}
    return wans*=flag;
}

int T;
int n,L,W;
struct node {double lx,rx;int pos,r;}a[N];
bool e666 (node x,node y){return x.lx<y.lx;}

int main (){
	T=wread();
	while (T--){
		memset (a,0,sizeof a);
		n=wread();L=wread();W=wread();
		for (int i=1;i<=n;++i){
			a[i].pos=wread(),a[i].r=wread();
			if (a[i].r*a[i].r-(W*1.0/2.0)*(W*1.0/2.0)<0)	a[i].pos=-1,a[i].lx=-1,a[i].rx=-1;
			//对于不能覆盖完草坪上端的一个圆(例如样例1中的那个夹在草坪中间的圆) 肯定是不会选它的 
			else {
				a[i].lx=max (0.000000,(double)a[i].pos-sqrt((double)a[i].r*(double)a[i].r-(W*1.0/2.0)*(W*1.0/2.0)));
				a[i].rx=a[i].pos+sqrt((double)a[i].r*(double)a[i].r-(W*1.0/2.0)*(W*1.0/2.0));					
			}
		}

		sort (a+1,a+n+1,e666);	
		
		int nx=1; 
		double s=0;//起点 
		bool F=true;//判断是否能覆盖完整个区间 
		int ans=0;//记录 
		
		while (nx<=n){
			ans++;
			double re=s;
			while (a[nx].lx<=re && nx<=n){//模板 
				if (a[nx].rx>=re)	s=max(s,a[nx].rx);
				nx++;
			}
			if (s>=L)	{break;}
			if (re==s)	{F=false;break;}//未更新,请画图____即当前区间与下个区间之间 一定有一段距离,不符合全部覆盖的要求,退出 
		}
		if (!F)	puts("-1");
		else	printf("%d\n",ans);
	}
	return 0;
}

未完待续...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《信息学奥赛一本提高》是一本针对信息学奥林匹克竞赛的学习资料,在提高信息学竞赛能力方面非常有帮助。这本书主要分为四个部分,包括基础知识、经典题型、解题技巧和实战训练。 首先,基础知识部分系统地介绍了信息学竞赛中常见的数据结构、算法和编程技巧。过深入理解这些基础知识,我们可以建立起解题的思维框架,提高解题的效率和准确度。 其次,经典题型部分列举了一些常见的信息学竞赛题型,并给出了详细的解题分析。过研究这些经典题目的解题思路和方法,我们可以学习到一些解题的常用套路和技巧,提高解题的能力。 接下来,解题技巧部分介绍了一些常用的解题技巧,如递推法、贪心算法、动态规划等。过学习这些解题技巧,我们可以更加灵活地应用不同的算法思想,解决更加复杂的竞赛题目。 最后,实战训练部分提供了大量的信息学竞赛题目和练习,帮助我们过实践巩固所学的知识和技巧。这些题目有不同的难度和类型,可以提供充分的练习机会,并提供了详细的解题思路和方法供参考。 总结来说,《信息学奥赛一本提高》是一本非常实用的学习资料,能够帮助学生提高信息学竞赛能力。过深入学习基础知识、研究经典题型、掌握解题技巧和进行实战训练,我们可以有效地提升在信息学竞赛中的表现,并取得更好的成绩。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值