首页 > 其他分享 >「Luogu P2466」[SDOI2008] Sue 的小球

「Luogu P2466」[SDOI2008] Sue 的小球

时间:2024-11-26 14:49:55浏览次数:4  
标签:std Sue int Luogu 彩蛋 P2466 区间 SDOI2008 Sandy

题目

Sue 和 Sandy 最近迷上了一个电脑游戏,这个游戏的故事发在美丽神秘并且充满刺激的大海上,Sue 有一支轻便小巧的小船。然而,Sue 的目标并不是当一个海盗,而是要收集空中漂浮的彩蛋,Sue 有一个秘密武器,只要她将小船划到一个彩蛋的正下方,然后使用秘密武器便可以在瞬间收集到这个彩蛋。然而,彩蛋有一个魅力值,这个魅力值会随着彩蛋在空中降落的时间而降低,Sue 要想得到更多的分数,必须尽量在魅力值高的时候收集这个彩蛋,而如果一个彩蛋掉入海中,它的魅力值将会变成一个负数,但这并不影响 Sue 的兴趣,因为每一个彩蛋都是不同的,Sue 希望收集到所有的彩蛋。

然而 Sandy 就没有 Sue 那么浪漫了,Sandy 希望得到尽可能多的分数,为了解决这个问题,他先将这个游戏抽象成了如下模型:

将大海近似的看做 \(x\) 轴,以 Sue 所在的初始位置作为坐标原点建立一个竖直的平面直角坐标系。

一开始空中有 \(N\) 个彩蛋,对于第 \(i\) 个彩蛋,他的初始位置用整数坐标 \((x_{i}, y_{i})\) 表示,游戏开始后,它匀速沿 \(y\) 轴负方向下落,速度为 \(v_{i}\) 单位距离/单位时间。Sue 的初始位置为 \((x_{0}, 0)\),Sue 可以沿 \(x\) 轴的正方向或负方向移动,Sue 的移动速度是 \(1\) 单位距离/单位时间,使用秘密武器得到一个彩蛋是瞬间的,得分为当前彩蛋的 \(y\) 坐标的千分之一。

现在,Sue 和 Sandy 请你来帮忙,为了满足 Sue 和 Sandy 各自的目标,你决定在收集到所有彩蛋的基础上,得到的分数最高。

Luogu

分析

一开始一直在想普通的 dp 究竟要怎么设状态,可是无论怎么设都无法在避免前面的彩蛋对后面所有彩蛋造成的影响,如果要避免的话复杂度里总是会有个坐标轴值域大小,显然会 T,而且初始位置在彩蛋的中间更不好按照彩蛋的顺序转移了,于是只好看题解。

第一篇题解引用了论文「对一类动态规划问题的研究」By 湖南省长沙市第一中学 徐源盛 ,主旨是如果当前的决策对未来的行动会造成影响,那么决策的时候就把影响计算出来就是了

不过在这之前,我们需要先注意到一点:从起点到当前位置的路径上的彩蛋是必然会拿的,这是很显然的,但是为什么我当时没有注意到啊 kora!,也就是说每次拿取到的彩蛋必然是一段区间,所以当然要用区间 DP 而不是普通的 DP 啦!

然后我们将论文中的思想运用到这道题中,其实思想也很 intuitive,感觉主要困扰我的是没有想到用区间 DP(哭)。在这道题中,我们设 \(f[i][j]\) 表示已经取得了区间 i 到 j 的彩蛋的得分,但是很快发现下一步拓展到 \(i-1\) 和 \(j+1\) 的计算结果会和当前的位置是在 \(i\) 还是 \(j\) 有关,这个简单,加一维分别表示最后是在左边还是右边就好了,于是有了 \(f[0][i][j]\) 和 \(f[1][i][j]\) 分别表示在 \(i\) 和在 \(j\)。

这样一来,状态转移方程就很简单了,如果是求 \(f[0][i][j]\),分别考虑是从 \(f[0][i+1][j]\) 还是 \(f[1][i+1][j]\) 拓展来的就好了。

假设彩蛋的收益是 \(y\),位置为 \(x\),我们已经取得了的彩蛋区间为 \([i,j]\),去取彩蛋 \(i\) 所需要的时间为 \(t\),那么对所有未取得的彩蛋的影响为 \(cost=(\sum_{k=1}^nv_k-\sum_{k=i+1}^jv_k)t\),于是有状态转移方程:

\[f[0][i][j]=y_i+\max(f[0][i+1][j]-cost*(x_{i+1}-x_i)),f[1][i+1][j]-cost*(x_j-x_i)) \]

第一维取值为 1 的状态转移方程也是类似的。

最后要吐槽的是我居然忘了区间 DP 枚举的第一维是区间长度而不是区间左边的值,如果按照区间 \([i,j]\) 这样来枚举 \(i\) 和 \(j\) 会导致两个都需要求的 \(f\) 互相调用对方的值来求得自己的值,这样就假了,因为每次转移是从区间长度小 1 的状态转移来的,把区间长度作为第 1 维进行枚举的话就可以保证每次转移依赖的值都是已经求解过的真值。

代码

#include <bits/stdc++.h>

using std::cin;	using std::cout;
using std::max; using i64 = long long;

const int N = 1005;

struct egg {
	i64 x, y, v;
} e[N];

int n;
i64 m;
i64 f[2][N][N], s[N];

int main() {
	std::ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	cin >> n >> m;
	for (int i = 1; i <= n; ++i) cin >> e[i].x;
	for (int i = 1; i <= n; ++i) cin >> e[i].y;
	for (int i = 1; i <= n; ++i) cin >> e[i].v;
	e[++n] = (egg){ m, 0, 0 };
	std::sort(e + 1, e + 1 + n, [](egg T1, egg T2) { return T1.x < T2.x; });

	int pos = 0;
	for (int i = 1; i <= n; ++i) {
		if (e[i].x == m) pos = i;
		s[i] = s[i - 1] + e[i].v;
	}
	memset(f, -0x3f3f3f3f, sizeof(f));
	f[0][pos][pos] = f[1][pos][pos] = 0;

	auto cost = [](int i, int j) { return s[n] - (s[j] - s[i - 1]); };

	for (int k = 1; k <= n; ++k) {
		for (int i = 1, j; i + k <= n; ++i) {
			j = i + k;
			f[0][i][j] = e[i].y + max(f[0][i + 1][j] - (e[i + 1].x - e[i].x) * cost(i + 1, j),
					f[1][i + 1][j] - (e[j].x - e[i].x) * cost(i + 1, j));
			f[1][i][j] = e[j].y + max(f[0][i][j - 1] - (e[j].x - e[i].x) * cost(i, j - 1),
					f[1][i][j - 1] - (e[j].x - e[j - 1].x) * cost(i, j - 1));
		}
	}

	printf("%.3lf", 1.0 * max(f[0][1][n], f[1][1][n]) / 1000);
	return 0;
}

标签:std,Sue,int,Luogu,彩蛋,P2466,区间,SDOI2008,Sandy
From: https://www.cnblogs.com/huangliwen/p/18570133

相关文章

  • 「Luogu P2501」[HAOI2006] 数字序列
    题目现在我们有一个长度为 \(n\) 的整数序列 \(a\)。但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列。但是不希望改变过多的数,也不希望改变的幅度太大。Luogu分析首先考虑subtask1:最小化要修改的数。如果正面思考一个数修改或不修改的答案,会发现答案......
  • 「Luogu P3953」[NOIP2017 提高组] 逛公园
    题目策策同学特别喜欢逛公园。公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有自环和重边。其中\(1\)号点是公园的入口,\(N\)号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间。策策每天都会去逛公园,他总是从\(1\)号点进去,从\(N\)号点......
  • 「Luogu P5441」【XR-2】伤痕
    人类智慧题,然而我是蒟蒻qwq.题目X国经历了一场前所未有的大地震,人们伤痕累累,整个国家破碎不堪。为了帮助人们痊愈,也为了让X国能够生存下去,X国国王决定重建X国。国王决定先建造\(n\)座城市,由于国王喜欢奇数,所以\(n\)为奇数。城市建造完后,需要给每两座城市之间都......
  • 「Luogu P4516」[JSOI2018] 潜入行动
    题目外星人又双叒叕要攻打地球了,外星母舰已经向地球航行!这一次,JYY已经联系好了黄金舰队,打算联合所有JSOIer抵御外星人的进攻。在黄金舰队就位之前,JYY打算事先了解外星人的进攻计划。现在,携带了监听设备的特工已经秘密潜入了外星人的母舰,准备对外星人的通信实施监听。外星......
  • 每日一题:https://www.luogu.com.cn/problem/P1106
    题目链接:https://www.luogu.com.cn/problem/P1106#include<iostream>#include<string>usingnamespacestd;intmain(){intn,k,mu;stringnum;intt=1,wei,ti=0;;intarr[260];boolyes=0;cin>>num>>k;n=num.l......
  • [luoguP1903] 数颜色
    题意原题链接给定序列\(a\),每次查询一个区间\([l,r]\)中有多少个不同的数,或进行单点修改。sol如果不修改的话,本题就是普通莫队[luoguSP3267]D-query由于有修改,所以需要再增加一维,记录这次查询是在多少次修改以后查询的,然后在莫队代码后面添加对修改次数的处理,即暴力修改......
  • [luoguP11324] Speaker
    题意原题链接给定一个带权无根树,第\(i\)个节点上有一个数\(c_i\),每次询问给定两个点\(x,y\),在无根树上任选一点\(z\),使\(c_x+c_y+c_z-dist(x,z)-dist(z,y)\)最大,输出最大的值。sol考虑\(z\)可能有两种情况,要么是\(x\toy\)的路径上的一点\(t\),要么从路径上的一点......
  • [luoguP11323] Happy Card
    题意原题链接有\(n\)种牌,第\(i\)种牌有\(a_i\)张,每次可以出\(1\)张(单牌)、\(2\)张(对子)或\(4\)张相同的牌(四炸),或是\(3\)张相同的牌及\(1\)张不同的牌(三带一),求把牌出完最少需要多少次。sol赛时看到这道题,就想到了[luoguP2668]斗地主,由于没有顺子,因此可以直接考虑......
  • [luoguSP3267] D-query
    题意给定\(n\)个数\(a_1\cdotsa_n\)和\(q\)个查询,每次查询区间\([l,r]\)中,\(a\)的不同数的个数sol本题不强制在线,因此可以考虑离线算法,如莫队。莫队是一个非常神奇的算法,它的基本思想是:将区间进行某种排序后,通过移动\(l,r\)指针,每次移动时处理答案的增减来得到答......
  • [lnsyoj1469/luoguP4644] Cleaning Shifts
    题意原题链接给定\(n\)个区间\([a_i,b_i]\),第\(i\)个区间拥有权值\(S_i\),求使用这些区间将区间\([M,E]\)(包含所有\(n\)个区间)完全覆盖(两端点不需要重合)所需区间的权值最小值。sol一道板子题,本来是数据结构优化DP,但是被最短路薄纱了。考虑将每一个时间点视作一个节......