F1的题目链接
F2的题目链接
题目大意
AA现在有n种装备要买,每个装备要买ki个,每一天的早上AA会赚到1元钱,每个装备的价钱都是2元,但是现在有m个特价活动(d1,ti)意思是在di天的时候第ti个装备只要1元钱,问你买完所有的装备所需的最小天数是多少?
F1 和 F2的题是一样的,只是数据范围不一样,我用的方法都是二分(log的时间复杂度)所以两个题的代码是一样的,都可以过。
解题思路
其实这个是一道二分题,和之前做的一个题晾衣服的题好像差不多,奈何我这个鱼脑子… …怎么就不长记性… … …
我们二分需要的天数,最小需要一天,最多需要的是每个装备都化2元钱要tot*2天,这里还是很好理解的,主要是怎么去判断mid天内能不能卖完这些装备呢:
我们设ans是现在有的钱,xi是第i个装备现在还有多少个没有买,那么钱就等于天数。我们先考虑可以特价买的商品的数量,因为能特价买的就特价买嘛,如果不能特价买就话2元买,这里感觉是个贪心:我们把能再mid天内搞特价的都存起来,然后按天数从小到大排序,一个个判断现在的钱够买多少个当前装备,xi减去能买的相应的数量,到最后xi剩的就是要两元买的数量了,用当前的钱数减去,如果最后的钱还大于等于0,就是可以买,否则就是不能买
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[500005],x[500005];
struct node
{
int d,t;
};
node e[500005],c[500005];
int n,m;
int cmp(node w,node p)
{
return w.d<p.d;
}
int F(int mid)
{
for(int i=1;i<=n;i++)
{
c[i].d=0;
c[i].t=i;
}
for(int i=1;i<=n;i++)
x[i]=a[i];
for(int i=1;i<=m;i++)
{
if(e[i].d<=mid)
{
int h=e[i].t;
c[h].d=max(c[h].d,e[i].d);
}
}
sort(c+1,c+1+n,cmp);
int ans=0,k=0;//k是上一次用钱的那天
for(int i=1;i<=n;i++)//贪心
{
int s=c[i].t;
ans+=c[i].d-k;
k=c[i].d;
if(ans>=x[s])
{
ans-=x[s];
x[s]=0;
}
else
{
x[s]-=ans;
ans=0;
}
}
if(k<mid)
ans+=(mid-k);
for(int i=1;i<=n;i++)
ans-=(x[i]*2);
return ans>=0;
}
int main()
{
int tot=0;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
tot+=a[i];
}
for(int i=1;i<=m;i++)
scanf("%d %d",&e[i].d,&e[i].t);
int l=1,r=tot*2,ans=0x3f3f3f3f;
while(l<=r)
{
int mid=(l+r)/2;
if(F(mid))
{
ans=min(ans,mid);
r=mid-1;
}
else
l=mid+1;
}
printf("%d\n",ans);
return 0;
}