题目链接:https://vijos.org/d/ybttg/p/5c24b83ff41362c9e19126c3
时间限制:1000 ms 内存限制:512 MiB

题目描述

老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为 10 10 10,要求在 6 6 6天内交,那么要想拿到这 10 10 10学分,就必须在第 6 6 6天结束前交。

每个作业的完成时间都是只有一天。例如,假设有 7 7 7次作业的学分和完成时间如下:

作业号 期限 学分
1 1 6
2 1 7
3 3 2
4 3 1
5 2 4
6 2 5
7 6 1

最多可以获得 15 15 15学分,其中一个完成作业的次序为 2 , 6 , 3 , 1 , 7 , 5 , 4 2,6,3,1,7,5,4 2,6,3,1,7,5,4,注意可能还有其他方法。
你的任务就是找到一个完成作业的顺序获得最大学分。

输入格式

第一行一个整数 N N N,表示作业的数量;

接下来 N N N行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。

输出格式

输出一个整数表示可以获得的最大学分。保证答案不超过 C / C + + C/C++ C/C++ i n t int int范围。

样例数据

样例输入

7
1 6
1 7
3 2
3 1
2 4
2 5
6 1

样例输出

15

限制与提示

对于 20 % 20\% 20%的数据, N ≤ 1 0 3 N \leq 10^3 N103

对于 40 % 40\% 40%的数据, N ≤ 1 0 4 N \leq 10^4 N104

对于 60 % 60\% 60%的数据, N ≤ 1 0 5 N \leq 10^5 N105

对于 100 % 100\% 100%的数据, N ≤ 1 0 6 N \leq 10^6 N106,作业的完成期限均小于 7 × 1 0 5 7\times 10^5 7×105

题解

题意:给你一些带有学分和时限的作业,在时限之内完成作业,就可以获得相应的学分,每个作业的完成时间都是只有一天,求能获得最大学分。
思路:我们先把作业按学分从大到小排个序。然后从第一份作业开始选择做与不做。如果在这一份作业的期限之前还有时间可以空闲,那就做这一份作业,在这里我们可以用一个优化,用一个链表f,f[i]指向f[i]之前的空闲时间。

Accepted Code:

/* 
 * @Author: lzyws739307453 
 * @Language: C++ 
 */
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
struct edge {
    int t, v;
    bool operator < (const edge &s) const {
        return s.v < v;
    }
}p[MAXN];
int fa[MAXN];
int find_fa(int v) {
    if (!~fa[v])
        return v;
    return fa[v] = find_fa(fa[v]);
}
int main() {
    int n, cnt = 0;
    scanf("%d", &n);
    memset(fa, -1, sizeof(fa));
    for (int i = 0; i < n; i++)
        scanf("%d%d", &p[i].t, &p[i].v);
    sort(p, p + n);
    for (int i = 0; i < n; i++) {
        int x = find_fa(p[i].t);
        if (x) {
            fa[x] = find_fa(x - 1);
            cnt += p[i].v;
        }
    }
    printf("%d\n", cnt);
    return 0;
}