Gadgets for dollars and pounds CodeForces - 609D 二分+贪心

本文介绍了一个结合二分查找与贪心策略解决特定购物问题的算法实现。该问题涉及利用有限货币在变动汇率下购买指定数量的商品,并求解最小购买天数及具体购买方案。文章详细解释了算法思路,包括预处理汇率、贪心选择最优购买时机等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题意:

现在有m个物品 每个物品有一个类型t(1 只能用美元买,2只能用英镑买) 和价钱c 你有s个卢卡斯,但是有的物品只能用美元来买有的只能用英镑来买,所以你需要拿卢卡斯来兑换.对应n天,每天有 美元的汇率 a,和英镑的汇率c(a卢卡斯兑换1美元..c.),问你能否在n天中从中买到k个物品,并输出最小需要多少天,并输出所购买的k件物品的id,以及在那一天购买的.

(每个物品只能买一次,但是一天可以购买多个物品)

思路:

这个题我们要二分天数,然后验证.即买够k个物品要多少天,也可以理解为最后购买的那件物品在第k天被买的.

那么我们怎么来验证呢?

贪心。

我们首先来思考一个问题,我们手中只有s卢卡斯的话,用它来兑换美元和英镑的话怎么样能兑换的最多?那么当然是

在美元和英镑的汇率a 和 c最小时我们一下子将s卢卡斯全部兑换,这时候我们获得钱是最多的然后在来购买物品.

   所以我们只需要提前预处理1...mid天当中 美元和英镑汇率的最小值(即兑换美元和英镑所需的最小卢卡斯)分别是多少,然后购买k件物品看其价钱和s的大小去二分答案即可.(对于每种商品按价格排序只贪心购买价钱最小的)

(最后根据我们二分找到的天数,得到了购买时英镑和美元的天数,然后分别去找到二者实际存在的位置,也就是第几天对应此汇率,然后最后输出结果,就找到了它们分别在哪一天购买的...)

   另外需要注意的是提前验证一下当n天都买不到k件物品则一定无解。

但是这个题当时我悲剧了...我无论怎么写显示的结果都不对的啊...但是我交了一发竟然ac了.....没错就是下面你的代码 ...我后来调试的时候发现二分的时候购买物品的if语句不会执行只执行else,然后我就在if中puts了1 也还是不显示...可是我交cf上显示输出了1啊...可能是我编译器炸了?可是我换了好多电脑了....

希望大佬告诉我哪里出现弱智错误了0.....0

#include<bits/stdc++.h>
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define inf 0x3f3f3f3f
#define exp 0.00000001
#define  pii  pair<int, int>
#define  mp   make_pair
#define  pb   push_back
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
ll gcd(ll a,ll b)
{
	return b==0?a:gcd(b,a%b);
}
struct node
{
	int id;
	ll w;
}d[2*maxn],p[2*maxn];
int n,m,k,c1,c2;
ll s;
ll dd[2*maxn],pp[2*maxn];
vector<pii>vt;
int cmp(node x,node y)
{
	return x.w<y.w;
}
int check(int x)
{
	vt.clear();
	ll cd=dd[x],cp=pp[x];
	ll ans=0;
	int id=0,ip=0;
	for(int i=1;i<=k;i++)
	{
			if((id<c1&&ip==c2)||(id<c1&&ip<c2&&cd*d[id].w<cp*p[ip].w))
			{     //puts("1");
				ans+=d[id].w*cd;
				vt.pb(mp(d[id].id,1));
				id++;
			}
			else
			{
				ans+=p[ip].w*cp;
				vt.pb(mp(p[ip].id,2));
				ip++;
			}
	}
	if(ans>s)
	return 0;
	return 1;
}
int main()
{
	int t;
	Ri(n),Ri(m),Ri(k),Rl(s);
	CLR(dd,inf);
	CLR(pp,inf);
	for(int i=1;i<=n;i++)
	{
		Rl(dd[i]);
		dd[i]=min(dd[i-1],dd[i]);
	}
	for(int i=1;i<=n;i++)
	{
		Rl(pp[i]);
		pp[i]=min(pp[i-1],pp[i]);
	}
	int tt;
	c1=0,c2=0;
	for(int i=1;i<=m;i++)
	{
		Ri(t),Rl(tt);
		if(t==1)
		{
			d[c1].id=i;
			d[c1++].w=tt;
		}
		else
		{
			p[c2].id=i;
			p[c2++].w=tt;
		}
	}
	sort(d,d+c1,cmp);
	sort(p,p+c2,cmp);
	if(check(n)==0)
	{
		Pi(-1);
	}
	else
	{
		int l=1,r=n,mid;
		while(l<=r)
		{
			mid=(l+r)>>1;
			if(check(mid))
			{
				r=mid-1;
			}
			else
			l=mid+1;
		}
		int d1=1,d2=1;
		while(dd[d1]>dd[l])
		d1++;
		while(pp[d2]>pp[l])
		d2++;
		Pi(l);
		//cout<<d1<<endl;
		for(int i=0;i<vt.size();i++)
		{
			//cout<<i<<' '<<vt[i].second<<endl;
			if(vt[i].second==1)
			printf("%d %d\n",vt[i].first,d1);
			else
			printf("%d %d\n",vt[i].first,d2);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marcus-Bao

万水千山总是情,只给五角行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值