码蹄杯 题型:反悔贪心

51 阅读1分钟

码题集OJ-AK IOI (matiji.net)

image.png

样例输入:

2 10
1 100
5 5

样例输出:

1

image.png

思想

要想在规定的m时间内尽可能多的通过Ak站点,那么就需要尽可能去挑AK时间少的站点去通过。

我们用一个大根堆去维护。

我们给所有的站点按照坐标从近到远排个序,然后我们由近到远去遍历站点。

如果一个站点的AK时间 + 之前遍历过的站点的AK时间 <=m,说明当前站点是一个合法的站点,我们把它计入到答案的贡献中。

反之,如果加上当前站点的AK时间已经大于m了,说明当前站点不可取,我们拿当前站点与 堆定站点对比一下,如果堆定站点AK时间更长,那么就从堆顶弹出,把当前站点加入堆顶。

这个就叫做反悔贪心。

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1E5+7;

struct NODE
{
	int x,t;  //坐标,时间 
}a[N];

bool cmp(NODE a,NODE b) 
{
  return a.x<b.x;	
}
priority_queue<int>q;
int n,m,sum;
signed main()
{
	cin>>n>>m;  //n个站点,时间限制m
	
	for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].t;
	
	sort(a+1,a+n+1,cmp);  //按照坐标从近到远排 
    
	for(int i=1;i<=n;i++)	
    {
    	if(sum+a[i].x+a[i].t<=m)
    	{
    		sum+=a[i].t;
    		q.push(a[i].t);
		}
		else if(!q.empty()&&sum-q.top()+a[i].x+a[i].t<=m)
	    {
	    	sum=sum-q.top()+a[i].t;
			q.pop();
			q.push(a[i].t); 
		}
	}
	cout<<q.size();
	return 0;
}

image.png