codeforces Gym 101341 K Competitions

来源:互联网 发布:孕囊后两个数据一样 编辑:程序博客网 时间:2024/05/19 15:22

Problem

codeforces.com/gym/101341/problem/K

vjudge.net/contest/162325#problem/K

Meaning

有 n 场比赛,每一场有:开始时间 a、结束时间 b、价值 c。问在这 n 场中挑选若干场,在使得总的价值最大的前提下,总的时长最短,要求任意两场比赛时间不能有重叠的部分(不算边界)。输出比赛场数、总价值、总时长、所选比赛编号。

Analysis

差不多就是《挑战程序设计竞赛(2e)》第 246 页的那题,虽然那题是网络流,但后面也有提这题的解法。

定义状态:

dp[i]:在时间 [ 0 , i ] 内能得到的最大价值;

len[i]:在得到上述最大价值的情况下的最短时长。

状态转移:用结束时间就是 i 的那些比赛来更新 dp[i]

dp[i] = max { dp[i-1] , dp[ a[j] ] + c[j] | 1 <=j <= n , b[j] = i } (j 表示第 j 个比赛,a、b、c 的意义同题目描述)

如果在 j 点更新了 dp[i],就有:len[i] = len[ a[j] ] + ( b[j] - a[j] );

若选 j 点得到与 dp[i] 一样的值,但能有更短时间,也要更新 len[i]。

时间范围很大,要进行离散化。

还要用个数组记录下当前时刻 i 选的是哪场比赛,好记录路经。

Code

#include <cstdio>#include <algorithm>#include <stack>using namespace std;const int N = 200000;struct node{int a, b, c;int l; // length = b - aint id; // 比赛编号,因为要排序,不能直接用下标表示编号node() {}node(int _b): b(_b) {}bool operator < (const node &rhs) const{return b < rhs.b;}} com[N];int ab[N<<1]; // 离散化数组int which[N<<1|1]; // 时刻i所选的比赛,记的是下标而不是编号long long dp[N<<1|1], len[N<<1|1];stack<int> stk;int main(){int n;scanf("%d", &n);int top = 0;for(int i=0; i<n; ++i){scanf("%d%d%d", &com[i].a, &com[i].b, &com[i].c);com[i].l = com[i].b - com[i].a;com[i].id = i + 1;ab[top++] = com[i].a;ab[top++] = com[i].b;}/* 离散化时刻 */sort(ab, ab + top);top = unique(ab, ab + top) - ab;for(int i=0; i<n; ++i){com[i].a = lower_bound(ab, ab+top, com[i].a) - ab + 1;com[i].b = lower_bound(ab, ab+top, com[i].b) - ab + 1;}/* 按结束时间排序,可二分找到结束时间为i的那些比赛 */sort(com, com + n);dp[0] = len[0] = 0;which[0] = -1;for(int i=1; i<=top; ++i){dp[i] = dp[i-1];len[i] = len[i-1];which[i] = which[i-1];int beg = lower_bound(com, com+n, node(i)) - com;for(int j=beg; j<n && com[j].b==i; ++j)if(dp[i] < dp[com[j].a] + com[j].c){dp[i] = dp[com[j].a] + com[j].c;len[i] = len[com[j].a] + com[j].l;which[i] = j;}else if(dp[i] == dp[com[j].a] + com[j].c &&len[i] > len[com[j].a] + com[j].l){len[i] = len[com[j].a] + com[j].l;which[i] = j;}}for(int i=top; ~which[i]; i=com[which[i]].a)stk.push(com[which[i]].id);printf("%d %I64d %I64d\n", stk.size(), dp[top], len[top]);for( ; stk.size(); stk.pop())printf("%d%c", stk.top(), stk.size()==1?'\n':' ');return 0;}

0 0