CF1379C.Choosing flowers

有 $𝑚$ 种物品,每种物品第一次买价值为 $𝑎𝑖$,以后每次买都是 $𝑏𝑖$。求买 $𝑛$件物品的最大总价值

要么都是第一次买的$a_i$,要么就是一堆$a_i$,$+k\times b_i$。

选四个。
证明:若$a_i>b_i>a_j$

$b_i>b_j$,显然$a_i+3b_i$
$b_i<b_j$, 显然$a_i+a_j+b_i+b_j<a_i+3b_j=a_i+a_j+3b_j$

就可以枚举$b_i$
需要注意的细节。

  • 二分出前面需要选更优秀的$a_j$,但是不要忘记,如果$a_i$一定要强制选上。
  • 若$pos>=n$,直接返回前缀和即可。
  • 手写二分吧,控制边界。
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0', c = getchar();
return x * f;
}

ll c[N], b[N], a[N];
ll sum[N];
int main()
{
int T = read();
while (T--)
{
int n = read(), m = read();

for (int i = 1; i <= m; i++)
a[i] = c[i] = read(), b[i] = read();
sort(1 + c, 1 + c + m, greater<int>());
for (int i = 1; i <= m; i++)
sum[i] = sum[i - 1] + c[i];
if (n == 1)
{
printf("%lld\n", c[1]);
continue;
}

ll ans = 0;
if (n <= m)
ans = sum[n];
for (int i = 1; i <= m; i++)
{
ll res = 0;
if (b[i] >= c[1])
{
res = a[i] + (n - 1) * b[i];
}
else
{
int l = 1, r = m, p = -1;
while (l <= r)
{
int mid = (l + r) >> 1;
if (c[mid] > b[i])
{
p = mid;
l = mid + 1;
}
else
r = mid - 1;
}
//cout << i << " " << p << endl;
if (n <= p)
res = sum[n];
else
{
if (a[i] < c[p])
res = (n - p - 1) * b[i] + sum[p] + a[i];
else
res = (n - p) * b[i] + sum[p];
}
}
ans = max(res, ans);
}
printf("%lld\n", ans);
}
}