codeforcr1130D

我的博客地址 :https://startcraft.cn
题目链接:http://codeforces.com/contest/1130/problem/D2

题目大意:有N个车站围成一个圆,火车按顺时针走,车站编号1-N,然后车站可能有人要去往某个车站,每次列车在一个车站只能带一个人,问你火车分别以1-N的车站为起点,最少需要多少时间把所有人带到目的地,火车花费一单位的时间从一个车站到另一个。

考虑从任意一个起点出发,走两圈之后一定可以将每个有人的车站中至少一人带到目的地
然后我们只需要考虑人最多的车站和比最多人数少1的车站,其他的车站在前面转圈的过程中,人已经全部到达目的地了,然后这些剩下的车站在前面转圈的过程中带走的是据目的地最远的人,因为前面在转圈的过程中会经过每一个车站,先把远一点的人带走,最后剩下一个近的人就可以少走一些路
人最多的车站和比最多人数少1的车站分别剩下两个人和一个人,然后比较从选定的起点开始,把剩下这些车站的剩下的人都送到目的地需要的时间,最长的时间就是剩下的人都送走需要的时间,最后一个送完的车站的人数-1就是转的圈数,所以最后答案加上圈数*n
找人数最多的车站可以通过排序完成,然后最近的人可以在输入的时候预处理

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
#define wfor(i,j,k) for(i=j;i<k;++i)
#define mfor(i,j,k) for(i=j;i>=k;--i)
// void read(ll &x) {
//  char ch = getchar(); x = 0;
//  for (; ch < '0' || ch > '9'; ch = getchar());
//  for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
// }
const ll INF = 0x7f7f7f7f;
struct st
{
    ll id;
    ll num;
};
struct rule
{
    bool operator ()(const st &x, const st &y)
    {
        return x.num > y.num;
    }
};
st station[5005];
ll minnum[5005];
int main()
{
    std::ios::sync_with_stdio(false);
#ifdef test
    freopen("F:\\Desktop\\question\\in.txt", "r", stdin);
#endif
#ifdef ubuntu
    freopen("/home/time/debug/debug/in", "r", stdin);
    freopen("/home/time/debug/debug/out", "w", stdout);
#endif
    ll n, m;
    cin >> n >> m;
    ll i;
    fill(minnum, minnum + n + 1, INF);
    wfor(i, 0, m)
    {
        ll a, cad;
        cin >> a >> cad;
        station[a].num++;
        station[a].id = a;
        minnum[a] = min(minnum[a], cad - a >= 0 ? cad - a : n + cad - a);//预处理最近的人
    }
    sort(station, station + n + 1, rule());//排序找人数最多的
    ll j;
    wfor(i, 1, n + 1)
    {
        ll ans = 0;
        ll num = station[0].num;
        ll lastst = station[0].id;//最后一个送完人的车站编号
        ll lastcha = 0;
        ll maxnum = station[0].num;
        wfor(j, 0, n)
        {
            if (station[j].num == maxnum || (station[j].num == maxnum - 1 && station[j].num > 0))//人最多的车站和比最多人数少1的车站
            {
                ll cha = station[j].id - i >= 0 ? station[j].id - i : n + station[j].id - i;//起点走到这个车站的距离
                cha += minnum[station[j].id];//将最近的人送走的距离
                if (station[j].num == station[0].num)//如果是人数最多的车站,它剩下两人,所以要多转一圈
                    cha += n;
                if (cha > lastcha)
                {
                    lastcha = cha;
                    lastst = station[j].id;//记录最后送完的车站编号
                    num = station[j].num;//记录最后送完的车站一共有几个人
                }
            } else
                break;
        }
        lastcha = lastst - i >= 0 ? lastst - i : n + lastst - i;
        ll fix = minnum[lastst];
        ans = (num - 1) * n + fix + lastcha;//最后送完的车站人数减一*n加上将最后一共人送走的距离加上选定的起点走到最后一共车站的距离
        cout << ans << " ";
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值