ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF607A Chain Reaction【dp+二分】

2021-07-01 07:00:06  阅读:251  来源: 互联网

标签:Reaction int 激光 坐标 摧毁 升序 激活 CF607A dp


原题链接

题意

给定 \(n\) 个激光塔,每个激光塔有一个坐标 \(a_i\) 和一个威力 \(b_i\),当第 \(i\) 个激光塔被激活后,坐标 \(\geq a_i-b_i\) 的激光塔将被摧毁。现在在所有激光塔的右侧放置一个坐标和威力任意的激光塔,从右到左依次激活没有被摧毁的激光塔,求最少要摧毁多少个激光塔。

思路

首先注意,虽然样例中的 \(a_i\) 都是升序给出的,但是题目中并未保证 \(a_i\) 升序,所以在最开始要进行排序

定义 \(f[i]\) 表示以第 \(i\) 个激光塔为起点,依次向右激活没被摧毁的激光塔,摧毁的激光塔数量。注意这里不能定义为最小值,因为本题中的起点一旦确定,那么摧毁的数量也就确定了。

注意到题目中给出的最右侧的激光塔的威力任意,其实就可以转化为摧毁第 \(i+1\) 个到第 \(n\) 个激光塔后,再以第 \(i\) 个激光塔为起点向右激活。那么最终的答案就是 \(\min(f[i]+n-i)\)。

接下来考虑状态转移方程。注意到,第 \(i\) 个激光塔被激活后,下一个被激活的肯定是第一个坐标小于 \(a_i-b_i\) 的激光塔,同时因为坐标是单调递增的,就可以用二分来查找这个激光塔 \(j\)。那么状态转移方程就是 \(f[i]=f[j]+i-j-1\)。因为在 \(j\) 和 \(i\) 之间的激光塔显然被摧毁了。

code:

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+10;
const int INF=0x3f3f3f3f;
struct NLC{
	int a,b;
    bool operator <(const NLC &t)const{
	    return a<t.a;
	}
}p[N];
int ans=INF,n,f[N];
int find(int x)
{
	int l=1,r=n;
	while(l<r)
	{
		int mid=l+r+1>>1;
		if(p[mid].a<x) l=mid;
		else r=mid-1;
	}
	return p[l].a<x?l:0;
}
int min(int a,int b){return a<b?a:b;}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d%d",&p[i].a,&p[i].b);
	sort(p+1,p+n+1);
	for(int i=1;i<=n;i++)
	{
		int j=find(p[i].a-p[i].b);
		f[i]=f[j]+i-j-1;
		ans=min(ans,f[i]+n-i);
	}
	printf("%d\n",ans);
	return 0;
}

标签:Reaction,int,激光,坐标,摧毁,升序,激活,CF607A,dp
来源: https://www.cnblogs.com/NLCAKIOI/p/14957154.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有