日常训练 20170612 星之船

探讨星之船停靠位置优化算法,旨在减少乘客上车时间。通过枚举特定位置,利用排序与遍历技巧,寻找最优停靠点及乘客上车总时间。

题目描述:
  站台的长度是 L,星之船最左侧的门称为第 1 个门,对于满足 1iN 的整数,星之船的第 i 个门与第 1 个门之间的距离是 Di,并且有 0=D1<D2<<DN1<DNL。站台上有 M 个乘客,对于满足 1iM 的整数,第 i 个乘客距离站台左边缘的距离为 Pi,那么有 0P1P2PML。如果星之船停在 S 这个位置,也就是说星之船的第 1 个门正对着站台的位置距离站台左边缘的距离是 S,那么由于所有的门都要正对站台,显然有 0SLDN。此时,星之船的第 i 个门正对站台的位置就是 S+Di
  如果第 i 个乘客从第 j 个门上车,由于星之船的体积巨大,门的大小可以忽略不计,那么他需要的时间就是 |Dj+SPi|。当然,所有的乘客都会选择需要时间最小的门上车。lqr目测了下一个停靠站台的情况,请你帮助她计算使得所有乘客上车时间最长的停靠位置 S,以及此时所有乘客上车所需的时间总和。
数据范围:
  0<L109,M300,N3000<L109,M300,N300
题解:
  L 很长,所以不能枚举每一个点,考虑有哪些必要枚举的点。可以证明只要枚举每个乘客在两个站点中点和车在最左和最右的位置就能找到解。考虑一个最优解车不在最左和最右位置并且没有乘客在两站点中点,那么每个乘客都有一个确定上车的门,我们对于每一个乘客找到使他能够多走一点的方向(就是他上的门的反向),对于两个方向,必然有一个方向能使乘客走的总路程至少不减,直到移到边缘或有人移到两站中点。

#include<bits/stdc++.h>
typedef long long ll;
const int N = 305;
int n, m, cnt;
ll L, P[N], D[N], S[N * N * 2];
void add(int x) {if (x >= 0 && x <= L - D[n]) S[++cnt] = x;}
int main() {
    scanf("%lld%d", &L, &m); L <<= 1;
    for (int i = 1; i <= m; i++)
        scanf("%lld", &P[i]), P[i] <<= 1;
    scanf("%d", &n);
    for (int i = 2; i <= n; i++)
        scanf("%lld", &D[i]), D[i] <<= 1;
    for (int i = 1; i <= m; i++)
        for (int j = 1; j < n; j++)
            add(P[i] - (D[j] + D[j + 1]) / 2);
    add(0); add(L - D[n]);
    std::sort(S + 1, S + cnt + 1);
    ll ans = 0, det;
    for (int k = 1; k <= cnt; k++) {
        int p = 1;
        ll tans = 0;
        for (int i = 1; i <= m; i++) {
            while (p < n && abs(D[p + 1] + S[k] - P[i]) < abs(D[p] + S[k] - P[i])) p++;
            tans += abs(D[p] + S[k] - P[i]);
        }
        if (tans > ans)
            ans = tans,
            det = S[k];
    }
    printf("%.1f %.1f\n", det * 0.5, ans * 0.5);
    return 0;
}

如有侵权,请联系作者删除。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值