【2018/08/22测试T3】【SDOJ 2821】shop

【题目】

题目描述:

有 n 种物品,第 i 种物品的价格为 vi,每天最多购买 xi 个。

有 m 天,第 i 天你有 wi 的钱,你会不停购买能买得起的最贵的物品。你需要求出你每天会购买多少个物品。

输入格式:

第一行两个整数 n , m。接下来 n 行每行两个整数 vi , xi。接下来 m 行每行一个整数 wi。

输出格式:

共 m 行,每行一个整数,第 i 行表示第 i 天购买的物品数量。

样例数据:

输入

3 3
1 1
2 2
3 3
5
10
15

输出

2
4
6

备注:

【数据规模】
对于 20% 的数据,n , m ≤ 1000。
对于另外 40% 的数据,xi = 1。
对于 100% 的数据,n , m ≤ 100000,1 ≤ vi ≤ 10^{9},1 ≤ xi ≤ 10000,0 ≤ wi ≤ 10^{18}

 

【分析】

20%:直接暴力模拟购物的过程,时间复杂度O(n * m)

另外 40%:先对 n 件物品按照价格排序(下面以从大到小为例),处理出前缀和。每次询问的时候,我们二分找出买得到的最贵的物品,再二分出能买得起的一段区间 i ~ j 。由于买下 i ~ j 的所有物品后就买不起第(j + 1)件,并且第(j + 1)件物品的价格小于等于第 j 件物品的价格,因此至少会花费一半的钱,所以时间复杂度O(n\cdot log\, n\cdot log\, w

100%:这个做法其实和40分做法类似,只改了一点,即每次二分能全部买下来的物品,再看下一个能买多少

 

【代码】

两次二分:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
struct node
{
	int v,x;
}p[N];
long long sum[N],num[N];
bool comp(const node &a,const node &b)
{
	return a.v>b.v;
}
int main()
{
//	freopen("shop.in","r",stdin);
//	freopen("shop.out","w",stdout);
	int n,m,i,l,r,mid,now;
	long long w,ans;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	  scanf("%d%d",&p[i].v,&p[i].x);
	sort(p+1,p+n+1,comp);
	for(i=1;i<=n;++i)
	{
		num[i]=num[i-1]+p[i].x;
		sum[i]=sum[i-1]+1ll*p[i].v*p[i].x;
	}
	for(i=1;i<=m;++i)
	{
		ans=now=0;
		scanf("%lld",&w);
		while(w>=p[n].v&&now<n)
		{
			l=1,r=n;
			while(l<r)
			{
				mid=(l+r)>>1;
				if(p[mid].v<=w)  r=mid;
				else  l=mid+1;
			}
			now=l,l--,r=n;
			while(l<r)
			{
				mid=(l+r+1)>>1;
				if(sum[mid]-sum[now-1]<=w)  l=mid;
				else  r=mid-1;
			}
			w-=sum[l]-sum[now-1];
			ans+=num[l]-num[now-1];
			if(l==n)  break;
			if(w>=p[l+1].v)
			{
				ans+=w/p[l+1].v;
				w%=p[l+1].v;
				now=l+1;
			}
			now=l;
		}
		printf("%lld\n",ans);
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

这是别的大佬用 lower_bound 实现的代码%%%:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
struct node
{
	long long v,x;
}p[N];
long long sum[N],a[N],b[N],num[N];
bool comp(const node &a,const node &b)
{
	return a.v<b.v;
}
int main()
{
//	freopen("shop.in","r",stdin);
//	freopen("shop.out","w",stdout);
	int n,m,i,now,pos,temp;
	long long w,ans;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	  scanf("%lld%lld",&p[i].v,&p[i].x);
	sort(p+1,p+n+1,comp);
	int tot=0;
	for(i=1;i<=n;++i)
	{
		if(p[i].v!=p[i-1].v)  p[++tot]=p[i];
		else  p[tot].x+=p[i].x;
	}
	n=tot;
	sum[n+1]=num[n+1]=0;
	for(i=n;i;--i)
	{
		sum[i]=sum[i+1]+p[i].x*p[i].v;
		a[n-i+1]=sum[i];
		b[i]=p[i].v;
		num[i]=num[i+1]+p[i].x;
	}
	for(i=1;i<=m;++i)
	{
                ans=0;
                scanf("%lld",&w);
		now=n-(lower_bound(a+1,a+n+1,w)-a)+2;
		w-=sum[now],ans+=num[now],--now;
		while(now>=1&&w>=p[1].v)
		{
			pos=now;
			now=lower_bound(b+1,b+now+1,w)-b;
			if((p[now].v>w)||now>pos)  --now;
			if(now<1)  break;
			temp=min(p[now].x,w/p[now].v);
			w-=p[now].v*temp,ans+=temp,--now;
		}
		printf("%lld\n",ans);
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/82148225