AtCoder Beginner Contest 137 D - Summer Vacation

D - Summer Vacation


Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 400 points

Problem Statement

There are N one-off jobs available. If you take the i-th job and complete it, you will earn the reward of BiBi after Ai 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 M days from today.

You can already start working today.

題意:

有N項工作,每一天你都可以選擇一項工作去完成(這些工作你都可以在一天內完成),一天你只能選擇完成一項任務,並且不能重複選擇已經完成的任務,每完成一個任務,你都可以在A天之後拿到報酬B,問在M天之內你能拿到的最大報酬(超過M天你就拿不到報酬了)。

PS:當時腦抽,題意都看錯了,傷心

Constraints

  • All values in input are integers.
  • 1≤N≤10^5
  • 1≤M≤10^5
  • 1≤Ai≤10^5
  • 1≤Bi≤10^4

Input

Input is given from Standard Input in the following format:

NN MM
A1 B1
A2 B2
⋮
AN BN

Output

Print the maximum total reward that you can earn no later than M days from today.


Sample Input 1 

3 4
4 3
4 1
2 2

Sample Output 1 

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 

5 3
1 2
1 3
1 4
2 1
2 3

Sample Output 2 

10

Sample Input 3 

1 1
2 1

Sample Output 3 

0

思路:

M天,第i天你都選擇A不超過M-i+1(確保能拿到報酬)的最大B(報酬最大)的任務就可以得到答案。

以下是某個大佬的代碼,借用以下:

#include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


struct FastIO{
  FastIO(){
    cin.tie(0);
    ios::sync_with_stdio(0);
  }
}fastio_beet;

//INSERT ABOVE HERE
signed main(){
  Int n,m;
  cin>>n>>m;
  vector<Int> as(n),bs(n);
  for(Int i=0;i<n;i++) cin>>as[i]>>bs[i];

  vector< vector<Int> > G(m+1);
  for(Int i=0;i<n;i++)//G[i]表示m-i天后,你能拿到報酬的任務有哪些 
    if(as[i]<=m) G[m-as[i]].emplace_back(bs[i]);

  Int ans=0;
  priority_queue<Int> pq;
  for(Int i=m;i>=0;i--){//i從m~0,也就是A從小到大選起
  /*這樣子確保了 第j天你選擇的任務的A不超過M-j+1(j從1~m)
  爲什麼呢, 反向思考一下
  最後一天,我們選A不大於1的B最大的一個任務
  倒數第二天,我們可以選A不大於2的B最大的一個任務
  		此時前面A不大於1的任務還有剩的話,當然也可以選
	    只要B最大就可以了
	其餘天雷同 
   這樣反過來選擇就能夠達到我們的要求 
  */ 
    for(Int x:G[i]){//每次循環按A從小到大把對應的B加進來 
    	pq.emplace(x);
	}
    if(!pq.empty()){//每次只選B最大的 
      ans+=pq.top();
      pq.pop();
    }
  }
  cout<<ans<<endl;
  return 0;
}

當然正向思考也是可以的,但是我想到的比較麻煩,從頭開始,A爲m的只能選擇一個,而如果沒有選擇A爲m的,A爲m-1的就可以選擇兩個,填補A爲m的位置,否則也只能選擇一個,其他的情況也是相同的。代碼我也沒寫,感覺比較麻煩。只是記錄一下新的思路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章