[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 822C: Hacker, pack your bags!【二分查找】【后缀最小值】
- Codeforces 496B Secret Combination(最小表示法)
- 【codeforces】704D. Captain America 【上下界最小流】
- POJ 1509 Glass Beads【后缀自动机、最小表示法】
- Codeforces 825F String Compression DP(最小循环节)
- Codeforces Good Bye 2015 D. New Year and Ancient Prophecy 后缀数组 树状数组 dp
- FZU 2165 v11(最小重复覆盖)+ codeforces 417D Cunning Gena
- codeforces contest 855 problem B(前缀后缀)
- CodeForces 292D Connected Components(并查集 前后缀)
- codeforces 632F. Magic Matrix (最小生成树)
- BZOJ.2882.工艺(后缀自动机 最小表示 map)
- codeforces 802I 后缀自动机
- Codeforces 500B New Year Permutation(更换位置,找最小字典数)
- 【codeforces 724D】【贪心】 Dense Subsequence 【一个字符串,按照一定的区间要求从中选出一些字符,使得这串字符的sort后字典序最小】
- [最小割] Codeforces 434D. Nanami's Power Plant
- CodeForces - 877B Nikita and string (前缀和后缀,任意删除)
- Codeforces 235C Cyclical Quest - 后缀自动机
- codeforces 235C Cyclical Quest(后缀自动机)
- codeforces 579D D. "Or" Game(前后缀+贪心)
- bzoj2882 工艺(后缀自动机(最小表示法))