CF1379C Choosing flowers 题解
题意:
有 \(m\) 种物品,每种物品有无限个,你可以购买 \(n\) 个物品。
对于第 \(i\) 种物品:
第一次买时的贡献是 \(a_i\) ,接下来每购买一个的贡献都是 \(b_i\)。即当你买了 \(x_i\) 个第 \(i\) 种物品时,贡献是 \(a_i+b_i \times (x_i-1)\)
现在要你求出最大贡献。
输入格式:
第一行一个 \(t (1≤t≤10^4)\),表示有 \(t\) 组数据。
对于每组数据:
第一行\(n\) 和 \(m (1≤n≤10^9,1≤m≤10^5)\)
接下来 \(m\) 行,每行两个整数\(a_i\)和\(b_i(0≤a_i,b_i≤10^9)\)
每组数据后有一个空行。
输出格式:
对于每组数据,输出一行一个整数表示最大的贡献。
容易发现,最优解一定只有一种物品被买了多次。
考虑枚举这个物品 \(i\) ,如果 \(i\) 被买了多次,则其他物品 \(k_i\) 一定有 \(a_{k_i} > b_i\) ,否则 \(i\) 不会被买多次
我们对物品按 \(a_i\) 排序并预处理前缀和,然后二分出第一个 \(a_k\) 大于 \(b_i\) 的 \(k\) ,再分类讨论即可。
时间复杂度 \(\mathcal{O}(n \log n)\)
代码:(别忘了判 \(k\) 不存在的情况)
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
typedef pair<int,int> pii;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5 + 15))
#define Fi first
#define Se second
pii a[N]; int sum[N];
void solve()
{
int n,m; cin >> m >> n;
for(int i = 1; i <= n; i++) { cin >> a[i].Fi >> a[i].Se; }
sort(a + 1, a + 1 + n);
for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i].Fi;
int res = 0;
for(int i = 1; i <= n; i++)
{
int l = 1, r = n;
while(l < r)
{
int mid = (l + r) >> 1;
if(a[mid].Fi > a[i].Se) r = mid; else l = mid + 1;
}
if(a[l].Fi <= a[i].Se) up(res, a[i].Fi + (m - 1) * a[i].Se);
else if(n - l + 1 >= m) up(res, sum[n] - sum[n - m]);
else if(l <= i) up(res, sum[n] - sum[l - 1] + (m - (n - l + 1)) * a[i].Se);
else up(res, sum[n] - sum[l - 1] + a[i].Fi + (m - (n - l + 1) - 1) * a[i].Se);
}
cout << res << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int qwq; cin >> qwq; while(qwq--) solve();
return 0;
}
参考文献: