您的位置:首页 > 其它

[codeforces] 854D. Jury Meeting(前/后缀最小值)

2017-09-08 00:13 295 查看

[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。

数据范围:

(1≤n,m≤105)

(1≤k,di,ci≤106)

(0≤fi,ti,≤n)

解题思路:

刚开始思路方向是 找一个位置i,i为到达时间, 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces