• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【线性DP】AcWing 4518. 最低票价

题目

https://www.acwing.com/problem/content/description/4521/

题解

对于该题,必须购买到能覆盖整个 \(days\) 数组的票。不妨假设 \(days = [x, y, z]\),很明显无论哪一种方案,从第 \(x\) 天开始购票都会是比较好的方案,因为在第 \(1\) ~ \((x - 1)\) 天不需要旅游,所以这些日期不需要购票。

维护一个大小为 \(n\) 的 \(dp\) 数组,\(dp[i]\) 代表到第 \(days[i]\) 天为止的最小开销,初始化为无穷大。

设在第 \(x\) 天,第 \(y\) 天,第 \(z\) 天的开销分别是 \(cost_x, cost_y, cost_z\)。此时,再思考一下 \(cost_x, cost_y, cost_z\) 的大小关系?

很明显必定会满足以下关系:\(cost_x <= cost_y <= cost_z\)。

既然存在上述大小关系,说明靠后的日期的开销必定大于等于靠前的日期的开销,所以从第 \(days[i]\) 天购买一张票价为 \(cost[j]\) 能够旅游 \(p\) 天的票,假设满足 \(days[k] \geq days[i] + p - 1\) 的最大下标为 \(k\),那么只需要维护 \(dp[k] = min(dp[k], dp[i - 1] + cost[j])\) 即可。

参考代码

#include<bits/stdc++.h>
using namespace std;

constexpr int INF = 0x3f3f3f3f;
int days[366], dp[366], costs[3], steps[3] = {0, 6, 29};
int n;

int main() {
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    cin >> n;
    fill(dp + 1, dp + 1 + n, INF);// 初始化每一天的开销都是无穷大
    for (int i = 1; i <= n; ++ i) cin >> days[i];// 输入日期数组
    for (int i = 0; i < 3; ++ i) cin >> costs[i];// 输入三种类型的票的售价
    for (int i = 1; i <= n; ++ i) {// 遍历每一个日期
        for (int j = 0; j < 3; ++ j) {// 遍历每一种票的类型
            // 在第 days[i] 天,购买售价为 cost[j] 的可旅行到第 days[i] + steps[j] 天为止的票
            int k = upper_bound(days + i, days + 1 + n, days[i] + steps[j]) - days - 1;// 计算出能旅游到的最后一天的下标
            dp[k] = min(dp[k], dp[i - 1] + costs[j]);// 计算出这一天的最小开销
        }
    }
    cout << dp[n] << '\n';
    return 0;
}

posted on 2025-05-18 21:36  RomanLin  阅读(11)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3