P3545 [POI2012]HUR-Warehouse Store
题目描述
\(n\) 天。第 \(i\) 天上午会进货 \(A_i\) 件商品,中午的时候会有顾客需要购买 \(B_i\) 件商品,可以选择满足顾客的要求,或是无视掉他。
如果要满足顾客的需求,就必须要有足够的库存。问最多能够满足多少个顾客的需求。
数据范围: 对于100%的数据,\(1\leq n\leq 250000,0\leq ai,bi\leq 10^9\)
这是一道很经典的贪心题
贪心策略:当能满足当前所有人时满足当前所有人。
但当不能满足时,就会出现错误。
那我们怎么保证贪心的正确行呢?
当我们不能满足时,我们可以看看前面的人,看看满足这个人是不是更优。
假如,当前这个人要比前面买的最多的人都要多,那我们可以不买给
这个人,以此来留下更多的商品,满足剩下的人。
如果比前面买的最多的人都要少,说明满足这个人要更优,
因为他可以剩下更多的商品,来满足剩下的人。
那我们就可以考虑维护一个大跟堆,每次把人的序号和他买的商品数
加入堆中,然后按照上述方法维护就行了。
几个注意的点
-
在删除大根堆堆顶时,一定要判断这个堆是否为空。否则就会疯狂RE
-
一定要开 long long(
不开long long见祖宗)
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#define LL long long
using namespace std;
LL n,ans;
LL a[300010],b[300010];
bool vis[300010];
priority_queue<pair<LL,int>, vector< pair<LL,int> > >q;//维护一个大根堆
int main()
{
scanf("%lld",&n); LL rest = 0;
for(int i = 1; i <= n; i++) scanf("%lld",&a[i]);
for(int i = 1; i <= n; i++) scanf("%lld",&b[i]);
for(int i = 1; i <= n; i++)
{
rest += a[i];
if(b[i] <= rest)//剩下的商品数,要比这个人买的要多,则可以满足
{
ans++;
q.push(make_pair(b[i],i));
rest -= b[i];//rest存剩下的商品数
vis[i] = 1;
}
else if(!q.empty() && b[i] < q.top().first)//一定要判堆是否为空
{
int t = q.top().second; q.pop();//去掉不优的堆顶
rest += b[t]; rest -= b[i];
vis[t] = 0, vis[i] = 1;//对要买的商品打标急
q.push(make_pair(b[i],i));
}
}
printf("%lld\n",ans);
for(int i = 1; i <= n; i++) if(vis[i]) printf("%d ",i);
return 0;
}