题目: The only difference between easy and hard versions is constraints.
Ivan plays a computer game that contains some microtransactions to make characters look cooler. Since Ivan wants his character to be really cool, he wants to use some of these microtransactions — and he won’t start playing until he gets all of them.
Each day (during the morning) Ivan earns exactly one burle.
There are nn types of microtransactions in the game. Each microtransaction costs 22 burles usually and 11 burle if it is on sale. Ivan has to order exactly kiki microtransactions of the ii -th type (he orders microtransactions during the evening).
Ivan can order any (possibly zero) number of microtransactions of any types during any day (of course, if he has enough money to do it). If the microtransaction he wants to order is on sale then he can buy it for 11 burle and otherwise he can buy it for 22 burles.
There are also mm special offers in the game shop. The jj -th offer (dj,tj)(dj,tj) means that microtransactions of the tjtj -th type are on sale during the djdj -th day.
Ivan wants to order all microtransactions as soon as possible. Your task is to calculate the minimum day when he can buy all microtransactions he want and actually start playing.
Input
The first line of the input contains two integers nn and mm (1≤n,m≤2⋅1051≤n,m≤2⋅105 ) — the number of types of microtransactions and the number of special offers in the game shop.
The second line of the input contains nn integers k1,k2,…,knk1,k2,…,kn (0≤ki≤2⋅1050≤ki≤2⋅105 ), where kiki is the number of copies of microtransaction of the ii -th type Ivan has to order. It is guaranteed that sum of all kiki is not less than 11 and not greater than 2⋅1052⋅105 .
The next mm lines contain special offers. The jj -th of these lines contains the jj -th special offer. It is given as a pair of integers (dj,tj)(dj,tj) (1≤dj≤2⋅105,1≤tj≤n1≤dj≤2⋅105,1≤tj≤n ) and means that microtransactions of the tjtj -th type are on sale during the djdj -th day.
Output
Print one integer — the minimum day when Ivan can order all microtransactions he wants and actually start playing.
Examples
Input
5 6
1 2 0 2 0
2 4
3 3
1 5
1 2
1 5
2 3
Output
8
Input
5 3
4 2 1 3 2
3 5
4 2
2 5
Output
20
题意:一个人每天早上可以得到一块钱,晚上可以用这些钱买一些商品。总共需要买n件物品,第i件需要买k[i]件。有m次则扣,d[i],t[i]表示若在d[i]买种类t[i]的商品,则需要1块钱。
非优惠期间买该商品一件需要两块钱。求最短的时间能买下所有的商品。
思路:
每件商品需要1或2块,最多2e5天可以买完。所以只要从大到小来枚举第i天是否能买完就行。可以轻松看出,如果第x天可以买完,那么超过x天肯定也可以买完。如果第x天买不完,那么低于x天肯定也买不完。因此可以考虑用二分来优化一下。
那么接下来就是要考虑第x天能不能买完。现在天数固定了。设想一下,你每天可以得到一块钱,你想买很多东西,有些可以晚点买,有些错过了今天,明天就没有优惠了,该怎么办?肯定是先把当天中有优惠的买了,如果后面几天到x天内还有这种商品有优惠,那么就不慌买,先把优惠期快过的买了。可以证明如果你不买这件商品,每天加一块钱并且可以存下来,那么过几天还可以买,可以腾出来这些钱买优惠期快过的,这样答案不会减少。
因此我们可以用一个late[i]数组纪录种类i的商品最后的优惠期在什么时候。对原数组按照天数排个序。1—m枚举.考虑第d[i]天,可以得到的钱为money+=d[i]-d[i-1]。如果最后优惠期late[]和当前的d[i]相等,那么就要去尽可能多的买这个商品。买的数量为k[i]和money中较小的。最后优惠的商品买完后,看看剩下的钱够不够剩余商品的2倍就行了。
注意事项:
(1) late数组每次都要清空,否则随着二分,late纪录的是上一次的东西,结果变大
(2) 只有当d[i]<=mid时才更新late[].
(3) 因为m个优惠中不一定都小于mid天。所以最后算剩余钱的时候money+=mid-last.
Last为最后一次满足d[i]<=mid的值
其他做法:
写check函数时枚举1—mid天,如果在i天有最后期限的商品,就尽可能的买
具体参见: https://www.cnblogs.com/AlphaWA/p/10928545.html
My code:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
int n,m;
int a[N],b[N],late[N];
struct node
{
int d,t;
bool operator <(const node &x)const
{
//if(d==x.d)return t<=x.t;
return d<x.d;
}
}s[N];
bool check(int mid)
{
int money=0,sum=0,last=0;
for(int i=1;i<=n;i++)
{
b[i]=a[i];
sum+=b[i];
late[i]=0;
}
for(int i=1;i<=m;i++)
if(s[i].d<=mid)late[s[i].t]=max(late[s[i].t],s[i].d);
for(int i=1;i<=m;i++)
{
if(s[i].d>mid)break;
last=s[i].d;
int d=s[i].d-s[i-1].d,t=s[i].t;
money+=d; //得到d[i]-d[i]天的钱
if(late[s[i].t]>s[i].d)continue; //若t[i]不是最后期限,那么就以后再买
if(money>=b[t]) //钱够,全买
{
money-=b[t];
sum-=b[t];
b[t]=0;
}
else //钱不够,把能买的都买了
{
sum-=money;
b[t]-=money;
money=0;
}
}
if(money+mid-last>=sum*2)return true; //剩下的所有的钱能否买剩下的商品
else return false;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)scanf("%d%d",&s[i].d,&s[i].t);
sort(s+1,s+1+m);
int l=1,r=4e5,ans=0;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}
本文介绍了如何使用二分搜索和贪心策略解决一个关于游戏内购的问题。玩家每天获得一定金额,需要在有限时间内购买不同类型的物品,物品有时会有优惠。目标是最短时间内购买所有物品。通过优化算法,可以确定购买所有物品的最短时间。

被折叠的 条评论
为什么被折叠?



