P2107 小Z的AK计划


题目描述

在小Z的家乡,有机房一条街,街上有很多机房。每个机房里都有一万个人在切题。小Z刚刷完CodeChef,准备出来逛逛。

机房一条街有 n 个机房,第 i 个机房的坐标为 xi ,小Z的家坐标为 0。小Z在街上移动的速度为1,即从 x1 到 x2 所耗费的时间为 |x1 − x2|。 每个机房的学生数量不同,ACM 题目水平也良莠不齐。小Z到达第 i 个机房后,可以花 ti 的时间想题,然后瞬间 AK;当然,也可以过机房而不入。

小Z现在只有 m 个单位时间,之后他就该赶着去打 Codeforces 了。现在他想知道自己最多能在多少个机房 AK,希望你帮帮他。

知识点
二叉堆
优先队列

输入格式:
第一行包含两个整数 n,m。

接下来 n 行,每行包含两个整数 xi,ti 。

输出格式:
第一行包含一个整数,表示小Z最多能 AK 的机房数量。

输入输出样例

输入样例#1:
2 10
1 100
5 5
输出样例#1:
1
说明

【数据规模】

对于 30% 的数据,n ≤ 20。

对于 60% 的数据,n ≤ 1000。

对于 100% 的数据,1 ≤ n ≤ 10^5,0 ≤ m,xi ≤ 10^18,0 ≤ ti ≤ 10^9。
这道题因为路径长度不定,若同时考虑路径长和思考时间两个因素会很麻烦,但是因为一条路绝对不会重复走(原因当然是浪费时间,还没有意义),所以我们可以考虑通过枚举使路径长这一因素变为一个固定值,这样我们只需要通过贪心来从小到大取思考时间即可,但这道题数据量比较大,则不能用插入排序(因为一定会超时),所以我们换一种考虑方式,使每次新进来的值加上我原来在上一个点所用的可以得到最多的AK机房数的几种情况中思考时间最少的时间加上路径所用时间,判断是否超时,同时,将此机房思考时间入队;若不超,则可将此机房添加到答案中去;若超时,则将所取的时间的队列中的最大值弹出,同时时间减去最大值
#include<bits/stdc++.h>
using namespace std;
const int ma=1e5+10;
struct zx{long long x;int y;};
zx s[ma];
long long a[ma],m;
int n,cnt,ans;
void su(int x)
{
while(x>>1>=1&&a[x>>1]<a[x])
{
swap(a[x>>1],a[x]);
x>>=1;
}
}
void sx(int x)
{
while(x<<1<=cnt)
{
int t=x,p=x<<1;
if(a[p]>a[t])
t=p;
if(p+1<=cnt&&a[p+1]>a[t])
t=p+1;
if(t==x)
break;
swap(a[t],a[x]);
x=t;
}
}
void add(int x)
{
a[++cnt]=x;
su(cnt);
}
void rm()
{
a[1]=a[cnt--];
sx(1);
}
bool cmp(zx c,zx d)
{
return c.x<d.x;
}
int main()
{
long long p=0,x;
int y,cn=0;
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld%d",&x,&y);
if(x<=m)//如果路程时间已经超过可用时间,那么到此机房为止所能AK的机房数一定为零,也就没有做的必要
{
s[++cn].x=x;
s[cn].y=y;
}
}
sort(s+1,s+1+cn,cmp);//按照路程排序
for(int i=1;i<=cn;i++)
{
p+=s[i].x+s[i].y-s[i-1].x;//加上这个机房的路径和思考时间,同时减去上一个机房的路径时间
add(s[i].y);//入队* (1)
ans++;
if(p>m)
{
ans--;
p-=a[1];//减去最大值*(2)
rm();//弹出* (3)
}
}
printf("%d",ans);
return 0;
}
带*号的步骤可用优先队列实现(这样就不用打上面的函数啦)
priority_queue<int,vector<int>,less<int> >q;
(1):q.push(s[i].y);
(2):p-=q.top();
(3):q.pop();

猜你喜欢

转载自www.cnblogs.com/LWL--Figthing/p/9108933.html