摆渡车

显然,这是一道 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;
}

 

posted on 2019-11-09 22:30  比特飞流  阅读(229)  评论(0编辑  收藏  举报

导航