【Codeforces Round #433 (Div. 1) B】Jury Meeting

【链接】h在这里写链接


【题意】


有n个人,它们都要在某一时刻开始,全都到达0位置,然后维持最少k个时间单位,然后再全都回到原来的位置;
第i个人初始的位置是i.
且一共有m班航班.
每一班航班,要么是从0出来的,要么是进入0的,且航班起飞的时间为di,出发地为fi,目的地为ti,花费为ci;
(航班当天到);
到或起飞的那一天不算k天中的一天。
问你每个人到达0,然后又回到各自位置的最小花费。

【题解】


考虑每个航班起飞的时间,把每个航班的信息加入到di时刻上.
vector <pair <int,int> >in[N];
存的是i时刻,进入0位置的飞机来自哪里,以及花费。
vector <pair <int,int> >out[N];
存的是i时刻,飞出0位置的飞机要到哪里,以及花费。
然后O(N)顺着扫和逆着扫两遍。
就能得到f1[i],num1[i];
f1[i]表示前i个位置,有num1[i]个人能到0位置,最小的花费是多少.
(时间顺序处理)
以及f2[i],num2[i];
f2[i]表示后n-i+1个位置,有num2[i]个人能回到原位置,最小的花费是多少;
(时间逆序处理就好)
以处理f1[i]为例。
进入i+1时刻的时候,看看i+1这个时间,有多少个航班到位置0,然后,看看某个人来0位置的花费能不能因此变少
(也即是不是那个人坐这班航班更优)
如果可以因此变少的话,f1[i]也能变少.
(如果那个人是第一次可以来0位置,那么num1[i]++)
用一个mi[N]来维护某个人到达0位置的最小花费就可以了。
(f2[i]用类似的方法维护就好)
然后枚举这n个人是何时开始全都到达0号位置的
f1[i]+f2[i+k+1]最小值就可以了;
(num1[i]和num2[i+k+1]都必须为n);

【错的次数】


0

【反思】


感觉很自然的思路。

【代码】

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6;

int n, m, k;
vector <pair <int, int > > in[N + 10], out[N + 10];
long long f1[N + 10], f2[N + 10];
int num1[N + 10], num2[N + 10];
int mi[N + 10], MI[N + 10];

int main() {
    ios::sync_with_stdio(0), cin.tie(0);

    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++) {
        int d, f, t, c;
        cin >> d >> f >> t >> c;
        if (t == 0)
            in[d].push_back(make_pair(f, c));
        else {
            //f == 0
            out[d].push_back(make_pair(t, c));
        }
    }

    for (int i = 1; i <= N; i++) {
        num1[i] = num1[i - 1];
        f1[i] = f1[i - 1];
        for (int j = 0; j <= (int)in[i].size() - 1; j++) {
            int from = in[i][j].first, cost = in[i][j].second;
            if (mi[from] == 0) {
                mi[from] = cost;
                num1[i]++;
                f1[i] += cost;
            }
            else {
                if (mi[from] > cost) {
                    f1[i] -= (mi[from] - cost);
                    mi[from] = cost;
                }
            }
        }
    }

    for (int i = N; i >= 1; i--) {
        f2[i] = f2[i + 1];
        num2[i] = num2[i + 1];
        for (int j = 0; j <= (int)out[i].size() - 1; j++){
            int to = out[i][j].first; int cost = out[i][j].second;
            if (MI[to] == 0) {
                MI[to] = cost;
                f2[i] += cost;
                num2[i]++;
            }
            else {
                if (MI[to] > cost) {
                    f2[i] -= (MI[to] - cost);
                    MI[to] = cost;
                }
            }
        }
    }

    long long ans = -1;
    for (int i = 1; i + k +1 <= N; i++) 
        if (num1[i]==n){
            if (num2[i + k + 1] == n) {
                long long temp = f1[i] + f2[i + k + 1];
                if (ans == -1) {
                    ans = temp;
                }
                else
                    ans = min(ans, temp);
            }
        }
    cout << ans << endl;
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值