ICode9

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

【ybt金牌导航1-2-4】免费馅饼

2021-01-25 21:34:57  阅读:258  来源: 互联网

标签:树状 int 最大值 ybt times 馅饼 金牌 式子


免费馅饼

题目链接:ybt金牌导航1-2-4

题目大意

有一个直线,在某一个时刻有一个馅饼会出现在一些位置,有它的价值。
一个人一开始可以站在直线的任意地方,然后他每个时刻可以不移动,或向任意一边移动一个单位或两个单位。

要你求这个人最多能拿多少价值的馅饼。

思路

我们看到这道题,弄出最普通的 dp。

\(f_i\) 为对于前 \(i\) 个馅饼,接住了第 \(i\) 个的最大贡献。

那就是枚举前面的每个点,还有不枚举,然后首先看能不能从那个点赶到这个点,然后就在可以的里面找最大值,然后加上这个点的贡献,就是 \(f_i\) 了。
那我们可以看出这是要馅饼按时间先后顺序排序。
而且看能否赶到,就要满足这个式子:(假设 \(i\) 赶到 \(j\),分别掉到格子的编号是 \(p_i\) 和 \(p_j\),掉的时间分别是 \(t_i\) 和 \(t_j\))
\(abs(p_i-p_j)\leq 2\times(t_j-t_i)\)

但是这样会超时,那我们考虑优化看馅饼的先后顺序的地方,看能不能通过这个先后顺序,直接快速地找到满足的点。

那我们考虑把式子化开,因为有绝对值,所有会有两个式子:
\(\left\{\begin{matrix} 2\times t_i+p_i\leq 2\times t_j+p_j&(p_i-p_j> 0)\\ 2\times t_i-p_i\leq 2\times t_j-p_j&(p_i-p_j\leq 0) \end{matrix}\right.\)
那它要分开两种,就很麻烦,我们但其实我们会发现,如果要的那个式子满足了,另一个也会满足。
那我们不妨让这两个式子都要满足。

那我们看怎么快速地找呢?
首先,因为两个式子的左右两边其实分别是 \(i,j\) 点的两个值,那我们可以一开始就算出来。
那我们考虑先按一个排好序,然后就只用判断另一个条件就可以了。

但是直接判断还是不行。
那我们考虑用一些数据结构来优化它。
那我们排好序之后,就要判断另一个值的大小关系。那只要大小关系,我们就可以把它离散化,不然值太大,数组装不下。

那离散化之后,怎么看大小呢?
我们想想,从小到大排序之后,意思就是可以从前面走到后面(当然这里是假设第二个条件都满足),那你现在就还要看第二个条件。
那就是当两个值,如果第一个值的位置比第二个值的位置靠前,而且第一个位置的第二个比较的值小于第二个值的第二个比较的值。那就是可以的。
你会发现它就是一个顺序对。

顺序对逆序对的这些玩意儿,自然就是树状数组。
当然,你用线段树也不是不可以,但是毕竟树状数组简单好打嘛。
(记得这个地方的地址是第二个匹配的值,因为树状数组地址其实就是一个匹配大小的东西,那就应该是最大贡献)

不过这个树状数组不是求逆序对个数或顺序对个数,而是在满足条件的地方取最大值。
那我们只要改一下,改成维护最大值即可。

那你就可以找到当你弄 \(f_i\) 的时候,最优是从哪里转移过来。
那至于 \(f_i\),就是最优还要加上拿到它这个馅饼能有的价值。

至于最后输出什么,就是所有最后结束的地方的最大值。那就是查询 \(1\sim num\) 中树状数组的最大值。(\(num\) 是离散化之后,有多少个不同的第二个匹配的值)
其实就是看找到最后选了哪里作为结尾使得价值最大。

那就是这样了。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

struct pie {
	int t, p, v, l, r, num;
}a[100001], b[100001];
int w, n, c[100001], now;
int tree[100001], re;

void add_num(int now, int addnum) {//树状数组(求最大值)
	for (int i = now; i <= c[0]; i += i & (-i))
		tree[i] = max(tree[i], addnum);
}

int quest(int now) {
	re = 0;
	for (int i = now; i; i -= i & (-i))
		re = max(re, tree[i]);
	return re;
}

bool cmp1(pie x, pie y) {
	return x.l < y.l;
}

bool cmp2(pie x, pie y) {
	return x.r < y.r;
}

int main() {
	scanf("%d %d", &w, &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d %d %d", &a[i].t, &a[i].p, &a[i].v);
		a[i].l = 2 * a[i].t - a[i].p;//算出比较依据
		a[i].r = 2 * a[i].t + a[i].p;
		a[i].num = i;
		
		b[i] = a[i];
	}
	
	sort(b + 1, b + n + 1, cmp2);
	c[1] = ++c[0];
	a[b[1].num].r = c[1];//离散化(对于我们第二个要比较的值)
	for (int i = 2; i <= n; i++) {
		if (b[i].r != b[i - 1].r) ++c[0];
		c[i] = c[0];
		a[b[i].num].r = c[i];
	}
	
	sort(a + 1, a + n + 1, cmp1);//先按第一个要比较的值排序,使枚举过去的时候第一个直接符合
	for (int i = 1; i <= n; i++) {
		now = quest(a[i].r);//比较第二个,找到比第二个比较的值比它更小中能获得的价值最大的
		add_num(a[i].r, now + a[i].v);//捡这个
	}
	
	printf("%d", quest(c[0]));//扫一遍全部,看全部方案中价值最大的
	
	return 0;
}

标签:树状,int,最大值,ybt,times,馅饼,金牌,式子
来源: https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_1-2-4.html

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

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

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

ICode9版权所有