Codeforces Round #657 (Div. 2)——C. Choosing flowers题解

2020/7/20
讲道理,这场Div2挺搞的。。。不过侥幸偷了50多分。嘻嘻,说正事:
题目:
Vladimir would like to prepare a present for his wife: they have an anniversary! He decided to buy her exactly n flowers.
Vladimir went to a flower shop, and he was amazed to see that there are m types of flowers being sold there, and there is unlimited supply of flowers of each type. Vladimir wants to choose flowers to maximize the happiness of his wife. He knows that after receiving the first flower of the i-th type happiness of his wife increases by ai and after receiving each consecutive flower of this type her happiness increases by bi. That is, if among the chosen flowers there are xi>0 flowers of type i, his wife gets ai+(xi−1)⋅bi additional happiness (and if there are no flowers of type i, she gets nothing for this particular type).
Please help Vladimir to choose exactly n flowers to maximize the total happiness of his wife.
大致题意:
有m种花,每种花有第一次购买获得的数值与第k次购买获得的数值(k>1),问你买n朵花获得的最大数值是多少。
总结:
明显感觉不算一道难题(虽然我也不会),做出来的人却没多人,可能是AB太毒瘤了。尝试过优先队列贪心(时间复杂度过大)和直接排序贪心(WA),最后看题解才知道,算是一道前缀和+二分题吧。
思路:
显而易见,购买k次以上(k>1)的花只会买一种(当然也有可能0种,后面再考虑一下即可)。那么只需要找到是哪种花购买1次以上,对于购买了k次的花记为x,则我们会发现如果少购买一次bx,去购买一个ai(ai>bx)则会使得总数值更高,因此对于每种bx,我们在购买它之前需要把所有ai>bx的花都先买下来。因此可以先按照ai进行排序,然后记录下ai的前缀和sum[i],之后枚举每一个bi,二分查找到最大的p使得ap>bi(即为最小的ap使得ap>bi),剩下的花就全部购买bi。
处理过程需要注意:

  1. 如果p>=n,则最多只能购买sum[n]而不是sum[p]
  2. 如果i>p,则说明当前bi对应的第一次购买ai还没有被购买,需要先购买一次ai,剩下的n-p-1次才能购买bi。
  3. 如果i<=p,剩下的n-p次全部购买bi。

代码:
(码风很飘,轻喷,可以去cf上面看看大佬的代码,或者自己写,大致思路如上)

#include<bits/stdc++.h>
using namespace std;
#define pll pair<long long, long long>
pair<long long, long long>x[100005];
long long sum[100005];
int upper(int l,int r,long long num)
{
	int ans = -1;
	while (l <= r)
	{
		int mid = (l + r) >> 1;
		if (x[mid].first > num)
		{
			ans = mid;
			l = mid + 1;
		}
		else r = mid - 1;
	}
	return ans;
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, m;
		cin >> n >> m;
		int i;
		for (i = 0; i < m; i++)
		{
			cin >> x[i].first >> x[i].second;
			sum[i] = 0;
		}
		sort(x, x + m, greater<pair<long long, long long>>());
		for (i = 0; i < m; i++)
		{
			//cout << x[i].first << ' ' << x[i].second << endl;
			if (i)sum[i] = x[i].first + sum[i - 1];
			else sum[i] = x[i].first;
		}
		long long ans = 0;
		for (i = 0; i < m; i++)
		{
			int p = upper(0, m-1, x[i].second);
			if (p != -1)
			{
				ans = max(ans, sum[min(p, n-1)] + (p < i ? max(0, n - p - 2) * x[i].second + (n>p+1?x[i].first:0) : max(0, n - p-1) * x[i].second));
			}
			else
			{
				ans = max(ans,  (n-1) * x[i].second + x[i].first);
			}
		}
		long long ans2 = 0;
		for (i = 0; i < m && n; i++)
		{
			ans2 += x[i].first;
			n--;
		}
		cout << max(ans2, ans) << endl;
	}
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值