题源:https://atcoder.jp/contests/abc137/tasks/abc137_d
Time Limit: 2 sec / Memory Limit: 1024 MB
Score : 400400 points
Problem Statement
There are NN one-off jobs available. If you take the ii-th job and complete it, you will earn the reward of BiBi after AiAi days from the day you do it.
You can take and complete at most one of these jobs in a day.
However, you cannot retake a job that you have already done.
Find the maximum total reward that you can earn no later than MM days from today.
You can already start working today.
Constraints
- All values in input are integers.
- 1≤N≤1051≤N≤105
- 1≤M≤1051≤M≤105
- 1≤Ai≤1051≤Ai≤105
- 1≤Bi≤1041≤Bi≤104
Input
Input is given from Standard Input in the following format:
NN MM
A1A1 B1B1
A2A2 B2B2
⋮⋮
ANAN BNBN
Output
Print the maximum total reward that you can earn no later than MM days from today.
Sample Input 1 Copy
Copy
3 4
4 3
4 1
2 2
Sample Output 1 Copy
Copy
5
You can earn the total reward of 55 by taking the jobs as follows:
- Take and complete the first job today. You will earn the reward of 33 after four days from today.
- Take and complete the third job tomorrow. You will earn the reward of 22 after two days from tomorrow, that is, after three days from today.
Sample Input 2 Copy
Copy
5 3
1 2
1 3
1 4
2 1
2 3
Sample Output 2 Copy
Copy
10
Sample Input 3 Copy
Copy
1 1
2 1
Sample Output 3 Copy
Copy
0
题解:
算法:贪心
题意概括:每天最多只能选择一个任务,但每天能同时做多个任务。因此,你需要把天数多的任务放在前面做,并贪心选择天数相同但收益高的任务来做。
解题思路:
首先,定义一个vector容器数组,用来装只能在第i或者第i天之前选择的任务。写一个for循环,从第m天依次往前选择任务。for循环里用了一个优先队列,用来贪心选择报酬最大的那个任务。for循环的内部实现了每次只选第i天可选任务中报酬最大的那个。而且,如果第i天有多个任务可选,而第i天前面没有任务可选,这时,肯定要从第i天的任务中选择若干个任务,优先队列依次取出队头元素,满足了这个条件,个中奥秘,自己体会~~
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
typedef long long ll;
vector<int> ve[maxn];//vector最好定义在外面,不然可能爆栈
int main()
{
// freopen("input.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,k;
cin>>n>>k;
int a,b;
for(int i=0;i<n;i++)
{
cin>>a>>b;
if(a>k) continue;//要有这个条件,不然下面的vector可能会成负值
ve[k-a+1].push_back(b);//表示只能在m-a+1天或者之前做
}
priority_queue<int> q;
int earn=0;
for(int i=k;i>=1;i--)//注意此处是从第k天开始往前推
{
for(int v:ve[i]) q.push(v);
if(!q.empty())
{
earn+=q.top();
q.pop();
}
}
cout<<earn;
return 0;
}
为什么上面有一个k'-a+1呢
假如现在有一个任务是3天的,而你的总时间是5天。
那你肯定最晚在第三天完成,5-3+1等于3,,类似的自己可以列举。
涉及知识点:
1、优先队列默认从大到小排序。
打破砂锅问到底。