(dp 优化)洛谷 P14460 寻雾启示 题解

题意

题目传送门,建议前往原题阅读题面、样例及其解释。

思路

设 f i f_i fi 表示走到位置 i i i 的最小话费。发现从起点开始能走多远,取决于在 0 0 0 处拿了多少铁,为了不浪费时间,每次回到 0 0 0、从 0 0 0 出发都只拿到达现阶段要到达的终点所需的铁。

那么显然有初始化 f i = i × ( k + t 1 ) f_i=i\times (k+t_1) fi=i×(k+t1)。

考虑转移,考虑前面某个阶段终点为 j j j 用完了所有的铁,现在想 j → 0 → i j\to 0\to i j→0→i。那么要从 j j j 走回 0 0 0 并且等到刷新出 i i i 块铁,然后以 t 2 t_2 t2 速度走到 j j j 在以 t 1 t_1 t1 速度走到 i i i,即:
f i ← max ⁡ ( f j + j × t 2 , i × k ) + j × t 2 + ( i − j ) × t 1 f_i\leftarrow \max(f_j+j\times t_2,i\times k)+j\times t_2+(i-j)\times t_1 fi←max(fj+j×t2,i×k)+j×t2+(i−j)×t1

为什么没有转移 f i ← f i − 1 + k + t 1 f_i\leftarrow f_{i-1}+k+t_1 fi←fi−1+k+t1 呢?因为走到 i − 1 i-1 i−1 不一定是从起点直接走到 i − 1 i-1 i−1,可能这段时间不足以刷新出一块石头,于是不能粗暴地加。

时间复杂度 O ( n 2 ) O(n^2) O(n2),然后就拿到了 90pts。

代码1(90pts,TLE*1)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+9,inf=0x3f3f3f3f;
ll Q,n,k,t1,t2;
ll f[N];//设走到i,不剩石头最优 
int main()
{
	scanf("%lld",&Q);
	memset(f,inf,sizeof(f));
	while(Q--)
	{
		scanf("%lld%lld%lld%lld",&n,&k,&t1,&t2);
		f[1]=k+t1;
		for(int i=2;i<=n;i++)
		{
			f[i]=i*k+i*t1;
			for(int j=1;j<i;j++)
			{
				f[i]=min(f[i],max(f[j]+j*t2,i*k)+j*t2+(i-j)*t1);
			}
		}
		for(int i=1;i<=n;i++)
		{
			printf("%lld ",f[i]);
			f[i]=inf;
		}
		puts("");
	}
	return 0;
}

考虑优化,发现 f i f_i fi 必然是单调递增的,而对于 j → 0 → i j\to 0\to i j→0→i 这个过程, j j j 越大这个过程就越长。于是考虑维护一个最优上一转移点(上一阶段终点) b e s bes bes,对于 j ∈ [ b e s , i ) j\in[bes,i) j∈[bes,i) 尝试 j → 0 → i j\to 0\to i j→0→i 更新 f i f_i fi 和 b e s bes bes,如果遇到一个 > f i >f_i >fi 的 j j j,那么后面的 j j j 都不优了,直接 break 掉。

不必探讨 b e s bes bes 前面的点了,因为选前面的点就会使 j × ( t 2 − t 1 ) j\times (t_2-t_1) j×(t2−t1) 的 j j j 变小, t 1 t_1 t1 远小于 t 2 t_2 t2 的情况已经涵盖在初始化 f i = i × k + i × t 1 f_i=i\times k+i\times t_1 fi=i×k+i×t1 了,所以此处 t 1 t_1 t1 远大于 t 2 t_2 t2,即 j j j 越小 j × ( t 2 − t 1 ) j\times (t_2-t_1) j×(t2−t1) 越大。并且你的 j j j 再小也得和 i × k i\times k i×k 取 max ⁡ \max max。

所以均摊下来是 O ( n ) O(n) O(n) 的。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls u<<1
#define rs u<<1|1
const ll N=1e5+9,inf=0x3f3f3f3f;
ll Q,n,k,t1,t2;
ll f[N],g[N];//设走到i,不剩石头最优 
int main()
{
	scanf("%lld",&Q);
	while(Q--)
	{
		scanf("%lld%lld%lld%lld",&n,&k,&t1,&t2);
		f[1]=k+t1;
		ll bes=0;
		for(int i=2;i<=n;i++)
		{
			f[i]=i*k+i*t1;
			for(int j=max(bes,1ll);j<i;j++)
			{
				ll tem=max(f[j]+j*t2,i*k)+j*t2+(i-j)*t1;
				if(tem<f[i])
				{
					f[i]=tem;
					bes=j;
				}
				else break;
			}
		}
		for(int i=1;i<=n;i++)
		{
			printf("%lld ",f[i]);
		}
		puts("");
	}
	return 0;
}
相关推荐
白狐_7988 分钟前
408数据结构第5章:树与二叉树②——遍历、线索树、森林与哈夫曼
数据结构·算法·深度优先
致Great3 小时前
科研人的 AI,不该只回答问题:我用字节TraeWork 跑了一遍真实研究任务
算法
纵有疾風起3 小时前
线性表的定义与基本操作 — 从逻辑结构到 ADT 接口
数据结构·算法·408·线性表·adt
测试_AI_一辰4 小时前
AI Agent 评测最隐蔽的坑-记忆
人工智能·算法·ai·自动化·ai编程
lucas_AI4 小时前
给YOLO检测器插 LoRA,'插对地方'比'插什么'更要命
人工智能·算法
LuminousCPP5 小时前
数据结构-时间与复杂度|时间/空间复杂度 + 两道力扣练习 + 二分查找复盘
c语言·数据结构·经验分享·算法·leetcode
Nil2085 小时前
leetcode 三数之和
数据结构·算法·leetcode
小小龙学IT5 小时前
C++ std::vector 底层实现深度解析:内存布局、扩容策略、移动语义与迭代器失效
开发语言·c++·算法
noipp5 小时前
推荐题目:洛谷 P16689 出征
java·开发语言·数据结构·c++·算法·洛谷·luogu
eBest数字化转型方案5 小时前
从工程视角拆解冰柜资产管理:拍照识别 pipeline、纯净度算法与 IoT 选型踩坑
人工智能·物联网·算法