【来源】
一本通题库-1430
LibreOJ-10008
vjudge
【题目描述】
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为 10 10 10,要求在 6 6 6天内交,那么要想拿到这 10 10 10学分,就必须在第 6 6 6天结束前交。
每个作业的完成时间都是只有一天。例如,假设有 7 7 7次作业的学分和完成时间如下:
作业号 | 期限 | 学分 |
---|---|---|
最多可以获得 15 15 15学分,其中一个完成作业的次序为 2 , 6 , 3 , 1 , 7 , 5 , 4 2,6,3,1,7,5,4 2,6,3,1,7,5,4,注意可能d还有其他方法。
你的任务就是找到一个完成作业的顺序获得最大学分。
【输入格式】
第一行一个整数
N
N
N,表示作业的数量。
接下来
N
N
N行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。
【输出格式】
输出一个整数表示可以获得的最大学分。保证答案不超过C/C++
的int
、Pascal
的longint
范围。
【输入样例】
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
【输出样例】
15
【数据范围】
对于 20% 的数据,
N
≤
1
0
3
N≤10^3
N≤103;
对于 40% 的数据,
N
≤
1
0
4
N≤10^4
N≤104;
对于 60% 的数据,
N
≤
1
0
5
N≤10^5
N≤105;
对于 100% 的数据,
N
≤
1
0
6
N≤10^6
N≤106,作业的完成期限均小于
7
×
1
0
5
7×10^5
7×105。
【解析1】
贪心。
先做学分大的作业。
将作业按学分从大到小排序,同分按时限降序。
假如学分最多的一个任务的完成期限是
k
k
k,我们应该放在小于等于
k
k
k的最靠后的时间段。
一旦出现一个不可能在规定期限内完成的时间,那就不做吧。
【代码1】
#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define RI register int
#define re(i,a,b) for(RI i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
#define MAX(a,b) (((a)>(b)) ? (a):(b))
#define MIN(a,b) (((a)<(b)) ? (a):(b))
using namespace std;
typedef long long LL;
int const N=1e6+5;
struct Node {
int t,m;
Node() {}
Node(int t,int m) : t(t),m(m) {}
bool operator < (const Node &rhs) const {
if(t!=rhs.t) return t>rhs.t;
return m<rhs.m;
}
} a[N];
int n,ans=0;
priority_queue <int> q;
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d%d",&a[i].t,&a[i].m);
sort(a+1,a+n+1);
int j=1;
for(int i=a[1].t; i>=1; i--) {
while(j<=n && a[j].t==i) {
q.push(a[j].m);
j++;
}
if(q.empty()) continue;
ans+=q.top();
q.pop();
}
printf("%d\n",ans);
return 0;
}
【解析2】
本题还可以用并查集。
按学分从大到小排序,那么我们会尽可能地让作业的完成时间延后,这样就能有更多空间给那些限制比较严格的作业。
设
f
[
i
]
f[i]
f[i] 为点
i
i
i 向左的最小空闲时间。
对于一个限制t的作业,我们将它放在
f
[
t
]
f[t]
f[t]上,同时使
f
[
t
]
=
f
[
t
]
−
1
f[t]=f[t]-1
f[t]=f[t]−1(表示这个时间被占用了)。
就可以用并查集维护了。
时间复杂度 O ( N l o g N + T ) O(N log N+T) O(NlogN+T),其中 T T T是最大期限
【代码2】
#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define RI register int
#define re(i,a,b) for(RI i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
#define MAX(a,b) (((a)>(b)) ? (a):(b))
#define MIN(a,b) (((a)<(b)) ? (a):(b))
using namespace std;
typedef long long LL;
int const N=1e6+5;
struct Node {
int t,m;
bool operator < (const Node &rhs) const {
return m>rhs.m;
}
} a[N];
int n,ans=0;
int fa[N];
inline int getfa(int x) {
if(x!=fa[x]) fa[x]=getfa(fa[x]);
return fa[x];
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d%d",&a[i].t,&a[i].m);
sort(a+1,a+n+1);
for(int i=1; i<=n; i++) fa[i]=i;
for(int i=1; i<=n; i++) {
int x=getfa(a[i].t);
if(x) ans+=a[i].m,fa[x]=getfa(x-1);
}
printf("%d\n",ans);
return 0;
}