NOIP2018T3(摆渡车)题解

题目信息

题目传送门

解题思路

法1:三维dp

dpijk:轮到第i个人的后j秒时间,一班车有k个人。

  • 第n个人一定是在tn到tn+m-1这段时间被接走的
  • 转移方程:
    定义di为第i个人个第i+1个人的时间差。
    ①考虑j的时间之外是否值得多花时间:
    dp[i][j][k] = dp[i + 1][j - d[i]][k + 1] + k * d[i](当j > di时)
    ②转移时间已有j,考虑多等一个人上车的两种情况:
    dp[i][j][k] = min(dp[i + 1][0][k + 1] + k * gap[i], dp[i + 1][max(0, j - d[i]) + m][1] + k * j)(当j > di时)

法2:一维dp

  • 我们可以认为时间是一条数轴,每名同学按照到达时间在数轴上排列。安排车辆将数轴分段,每段长度≥m。原来的等车时间和,就变成了所有点到个子段右边界的距离。
  • 状态转移方程:
    定义a为前缀和数组。
    dp[i] = min j ≤ i - m(dp[j] + (a[i] - a[j]) * i - sum[i] + sum[j])
  • 优化:前缀和。
    特别提醒: 未吸氧的话只能得70pts,后面会TLE。

代码实现

法1

#include <bits/stdc++.h>
using namespace std; 
const int N = 4000005;
int a[N], s[N], dp[N];
int main() {
    ios :: sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n, m, t = 0;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        ++a[x];
        s[x] += x;
        t = max(t, x);
    }
    for (int i = 1; i < t + m; ++i) {
        a[i] += a[i - 1];
        s[i] += s[i - 1];
    }
    for (int i = 1; i < t + m; ++i) {
        dp[i] = a[i] * i - s[i];
        for (int j = max(i - 2 * m + 1, 0); j <= i - m; ++j) {
            dp[i] = min(dp[i], dp[j] + (a[i] - a[j]) * i - (s[i] - s[j]));
        }
    }
    int res = INT_MAX;
    for (int i = t; i < t + m; ++i) {
        res = min(res, dp[i]);
    }
    cout << res << '\n';
    return 0;
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒟蒻一枚

谢谢鸭~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值