[codeforces] 854D. Jury Meeting(前/後綴最小值)

[codeforces] 854D. Jury Meeting


題目鏈接:
D. Jury Meeting

題目大意:
有n個人分別在1~n的點上, 要讓這n個人到0號點並且所有人在一起的天數至少爲k天, 之後再回到各自的點。 有m個航班, d f, t, c 表示第d天從u到v的花費爲c, 其中f, t 必有一個是0。
輸出最小花費, 如果不能滿足輸出-1。

數據範圍:

(1n,m105)

(1k,di,ci106)

(0fi,ti,n)

解題思路:

剛開始思路方向是 找一個位置ii 爲到達時間, i+k+1 是最早離開時間。 找i 以及之前所有人到達的的最小和加上i+k+1 天開始往後所有人離開的最小和。

我們先將所有航班按照日期排序, 正着掃一遍, 就可以維護第i天所有人到達0號點的最小和。 倒着掃一遍, 就是所有人第i天開始離開的最小和。
具體維護方法:每個人總是維護一個最小花費, n個人都出現過之後纔開始更新f[i]
完事之後遞推一遍更新。(更新前綴最小和)
倒着的同理。。 代碼思路很清晰。
前綴和後綴都處理完之後我們就可以枚舉位置維護答案了。

代碼:

/********************************************
 *Author*        :ZZZZone
 *Created Time*  : 四  9/ 7 22:09:41 2017
 *Ended  Time*  : 四  9/ 7 23:04:05 2017
*********************************************/
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int , int> PII;
const int MaxN = 1e5, MaxV =  1e6;
const LL inf = 1LL << 60;

int n, m, k;
struct NODE{
    int d, u, v, c;
}box[MaxV + 5];

int ok[MaxN + 5];
LL f[MaxV + 5], t[MaxV + 5];


bool cmp(NODE x, NODE y){
    return x.d < y.d;
}

int main(){
    while(~scanf("%d %d %d", &n, &m, &k)){
        for(int i = 1; i <= m; i++)
            scanf("%d %d %d %d", &box[i].d, &box[i].u, &box[i].v, &box[i].c);
        sort(box + 1, box + m + 1, cmp);
        LL tot = 0;
        for(int i = 1; i <= 1e6; i++) f[i] = t[i] = inf;
        for(int i = 1; i <= m; i++){//前綴
            if(box[i].u == 0) continue;
            if(ok[box[i].u] == 0){
                ok[0]++;
                ok[box[i].u] = box[i].c;
                tot = tot + 1LL * box[i].c;
            }
            else{
                tot = tot - ok[box[i].u];
                ok[box[i].u] = min(ok[box[i].u], box[i].c);
                tot = tot + ok[box[i].u];
            }
            if(ok[0] == n) f[box[i].d] = tot;//n個人都到達了才更新
        }
        for(int i = 2; i <= 1e6; i++) f[i] = min(f[i], f[i - 1]);// 遞推維護前綴
        memset(ok, 0, sizeof(ok));
        tot = 0;
        for(int i = m; i >= 1; i--){
            if(box[i].v == 0) continue;
            if(ok[box[i].v] == 0){
                ok[0]++;
                ok[box[i].v] = box[i].c;
                tot = tot + 1LL * box[i].c;
            }
            else{
                tot = tot - ok[box[i].v];
                ok[box[i].v] = min(ok[box[i].v], box[i].c);
                tot = tot + ok[box[i].v];
            }
            if(ok[0] == n) t[box[i].d] = tot;
        }
        for(int i = 1e6 - 1; i >= 1; i--) t[i] = min(t[i], t[i + 1]);
        LL ans = inf;
        for(int i = 1; i <= 1e6 - k - 1; i++){
            if(f[i] != inf && t[i + k + 1] != inf)
                ans = min(ans, f[i] + t[i + k + 1]);
            //printf("%lld %lld\n", f[i], t[i]);
        }
        if(ans != inf) printf("%lld\n", ans);
        else printf("-1\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章