NOIP201803摆渡车
题目链接:https://hdnoip.com/problem/P0313
分析
状态: dp[i]表示在i这个时刻,车在人大附中,最小的等车时间和
易得 状态转移方程为:
d p [ i ] = m i n ( d p [ j ] + [ j , i ] 时 刻 之 间 的 等 车 时 间 和 ) ( 0 < = j < i )
时间复杂度: O ( n^3 )
for (i: 1 ~ n) {
for (j: 1 ~ i - 1)
{
int cnt = 0;
for (k: j ~ i)
{
cnt += k时刻到来的人所需等待的时间
}
dp[i] = min (dp[i], dp[j] + cnt);
}
}
ATTENTION:
最终的答案不在 d p [ m a x ( t [ i ] ) ] 里,因为将时间第二大的人送走后返回到人大附中的时间是
第 二 大 的 时 间 + m
所以答案应该为
m i n ( d p [ i ] ) 其中:m a x ( t [ j ] ) < = i < m a x ( t [ j ] ) + m
优化
1.我们先分析车,车的停留时间是不会超过m的(因为Ta可以在相同的状态下多跑一趟,这肯定比少跑一趟的结果优)
2.我们能不能用更快的时间去计算出[j, i]时刻之间的等车时间和呢?答案是可以的,我们可以用一个前缀和数组来实现,具体操作见下
for (int i = 1; i <= n; i++) { scanf ("%lld", &a[i]); r = Max (r, a[i]); prenum[a[i]]++; pret[a[i]] += a[i]; } for (int i = 1; i < r + m; i++) prenum[i] += prenum[i - 1], pret[i] += pret[i - 1]; (prenum[i] - prenum[j]) * i - (pret[i] - pret[j])即为[j, i]时刻之间的等车时间和
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=5000005;
int t[maxn],num[maxn],st[maxn],f[maxn];int T=0;
int main()
{
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
num[t[i]]++;
T=max(T,t[i]);
st[t[i]]+=t[i];
}
for(int i=1;i<=T+m-1;i++) num[i]+=num[i-1];st[i]+=st[i-1];
int minv=0x3f3f3f3f;
for(int i=1;i<=T+m-1;i++)
{
if(i>=m&&num[i-m]==num[i]) {f[i]=f[i-m];continue;}//中间没有点,直接转移即可
f[i]=num[i]*i-st[i];
for(int j=i-m;j>=max(0,i-2*m);j--)
{
f[i]=min(f[i],f[j]+(num[i]-num[j])*i-(st[i]-st[j]));
}
}
for(int i=T;i<=T+m-1;i++) minv=min(minv,f[i]);
printf("%d",minv);
return 0;
}

浙公网安备 33010602011771号