[Luogu] CF1379C Choosing flowers

\(Link\)

Description

\(m\)种物品,每种物品有无限个,你可以购买\(n\)个物品。

对于第\(i\)种物品:​第一次买时的贡献是\(a_i\) ,接下来每购买一个的贡献都是\(b_i\)。即当你买了\(x_i\)个第\(i\)种物品时,贡献是 \(a_i+b_i \times (x_i-1)\)

现在要你求出最大贡献。

Solution

这道题有一个重要的性质,就是我们要么不买\(b_i\),要么只买一种\(b_i\)。证明:不妨设买第\(i\)种物品\(t_i\)个和第\(j\)种物品\(t_j\)个,且\(b_i\ge{b_j}\)。假设\(t_i>1,t_j>1\),此时贡献为\(a_i+b_i(t_i-1)+a_j+b_j(t_j-1)\)。而如果只买一个第\(i\)种物品,买\(t_i+t_j-1\)个第\(j\)种物品,贡献为\(a_i+a_j+b_j(t_i+t_j-2)\),贡献更大。

还有一个性质,就是如果我们选择买一种\(b_i\),那么\(\le{b_i}\)\(a_j\)必定不选,\(>b_i\)\(a_j\)必定要选。

这样我们就可以二分了(就是重载小于号\(lower\_bound\)

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int t, n, m;

ll res, s[100005];

struct node
{
	int a, b;
}obj[100005];

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
	return x * fl;
}

bool operator < (const node &a, const node &b)
{
	return a.a > b.a;
}

int main()
{
	t = read();
	while (t -- )
	{
		n = read(); m = read();
		for (int i = 1; i <= m; i ++ )
		{
			obj[i].a = read();
			obj[i].b = read();
		}
		sort(obj + 1, obj + m + 1);
		for (int i = 1; i <= m; i ++ )
			s[i] = s[i - 1] + (ll)obj[i].a;
		res = s[min(n, m)];
		for (int i = 1; i <= m; i ++ )
		{
			int pos = lower_bound(obj + 1, obj + m + 1, (node){obj[i].b, 0}) - obj - 1;
			if (pos < i && pos <= n - 1) res = max(res, s[pos] + obj[i].a + 1ll * (n - pos - 1) * obj[i].b);
			else if (pos <= n) res = max(res, s[pos] + 1ll * (n - pos) * obj[i].b);
 		}
		printf("%lld\n", res);
	}
	return 0;
}
posted @ 2020-11-21 14:11  andysj  阅读(50)  评论(0编辑  收藏  举报