惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
D
DataBreaches.Net
F
Fortinet All Blogs
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
Apple Machine Learning Research
Apple Machine Learning Research
H
Help Net Security
M
MIT News - Artificial intelligence
美团技术团队
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Cloudflare Blog
有赞技术团队
有赞技术团队
L
LangChain Blog
博客园 - Franky
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 【当耐特】
S
SegmentFault 最新的问题
V
Visual Studio Blog
Blog — PlanetScale
Blog — PlanetScale
Hugging Face - Blog
Hugging Face - Blog
B
Blog
I
InfoQ

博客园 - 比特飞流

ubuntu 实现远程登录 远程Ubantu Mysql安装 + 本地Windows Navicat连接 Ubuntu安装Lamp jquery 中each退出循环和跳出循环 javascript 对话框 时间 Delphi 解析HTML 小雨的矩阵 数数游戏 银行排队机 纸牌游戏 逆波兰表达式 表达式求值 几种排序算法 Cena评测系统在win10中测评cpp程序 素数算法 动态规划 树状数组 数论
摆渡车
比特飞流 · 2019-11-09 · via 博客园 - 比特飞流

显然,这是一道 DP  题。
于是设 f[i] 表示第 i 分钟发出一辆车所要的最小时间,设 t为最后一个人到达车站的时间。

得到状态转移方程:

其中 k 表示上一辆末班车发车的时间。

那么最后的答案即为:ans=min{f[i]}(t≤i<t+m) 
i<t+m 是因为最后一个人等的时间不会超过 m  分钟,不然他可以直接乘之前的一辆走,肯定不是最优解。

时间复杂度: Θ(t2n)

优化
1、前缀和优化
令 cnt[i] 表示到 i 止到达车站的人数和
sum[i]表示到 i为止到达车站的人的时间总和
显然有:

即,总等待时间 = i×(i∼k内总人数) − 等待时间在 i∼k  内所有人的等待时间之和。

附上一张图帮助理解:

于是方程变为:

时间复杂度:Θ(t2

2、转移优化
显然,没有一位同学的等待时间会超过 2m 分钟。

简单证明:
考虑最坏的情况,在 k  时刻发了一辆车,有个同学在 k+1 时到达车站,那么摆渡车将在 k+m 时返回,考虑到等待其它学生的情况,摆渡车最晚会在 k+2m−1时发车,否则还不如分别在 k+m 和 k+2m  的时候发出。

所以, k 的范围就变为: i−2m<k≤i−m。

时间复杂度: Θ(tm)

#include<bits/stdc++.h>
#define ll long long
#define me(x) memset(x,0,sizeof(x))
#define bi(x) memset(x,0x3f,sizeof(x))
#define ud  using namespace std
ud;
const int maxn=1e7+10; int last_time=-9876543,ans=1<<30;
int N,M,t[maxn],f[maxn],sum[maxn]={},cnt[maxn]={};

int main()
{
    scanf("%d",&N);
    scanf("%d",&M);
    for(int i=1;i<=N;++i) 
    {
        scanf("%d",&t[i]);
        // Find the last person who reach the station
        last_time=max(last_time,t[i]);
        ++cnt[t[i]];//从0到i时间为止到达车站的人数和
        sum[t[i]]+=t[i];//从0到i时间为止到达车站的人的时间总和
    }
    for(int i=1;i<last_time+M;++i)
    {
        cnt[i]+=cnt[i-1];
        sum[i]+=sum[i-1];
    }
    for(int i=0;i<last_time+M;++i)
    {
        if(i>=M&&cnt[i-M]==cnt[i])
        {
            f[i]=f[i-M]; continue;
        }
        f[i]=cnt[i]*i-sum[i];
        for(int j=max(i-(M<<1)+1,0);j<=i-M;++j)
        f[i]=min(f[i],f[j]+(cnt[i]-cnt[j])*i-(sum[i]-sum[j]));
    } 
    for(int i=last_time;i<last_time+M;++i) ans=min(ans,f[i]);
    printf("%d\n",ans);
    return 0;
}