思路
对于每种商品,如果不用优惠券购买,花费 \(A_i\),并获得一张优惠券;如果使用优惠券,花费 \(B_i\)。
因为 \(B_i<A_i\),所以对于某个商品来说,使用优惠券可以节省 \(A_i-B_i\) 元。
因此我们可以先考虑:假设最终有 \(i\) 种商品使用优惠券购买,那么应该把优惠券用在哪些商品上。
显然应该选择 \(A_i-B_i\) 最大的 \(i\) 种商品,这样节省的钱最多。
令所有商品先都按照原价购买一次,总花费为 \(s=\sum A_i\)。
再把所有 \(c_i=A_i-B_i\) 从大到小排序。
设前 \(i\) 个的和为 \(x\),那么如果这 \(i\) 种商品使用优惠券,本来可以把花费降低到 \(s-x\)。
优惠券从哪来
问题在于,使用 \(i\) 张优惠券之前,我们必须先获得至少 \(i\) 张优惠券。
在最终购买的 \(N\) 种商品中:
- 有 \(i\) 种使用优惠券购买,不会获得优惠券;
- 剩下 \(N-i\) 种不用优惠券购买,可以获得 \(N-i\) 张优惠券。
因此如果 \(N-i\ge i\),那么现有这些购买已经可以产生足够的优惠券,不需要额外购买商品。
也就是当 \(2i\le N\) 时,不需要额外花费。
如果 \(2i>N\),那么还缺少 \(i-(N-i)=2i-N\) 张优惠券。
每多买一次不用优惠券的商品,就可以获得一张优惠券。
为了使额外花费最小,显然每次都购买 \(A_i\) 最小的商品。
设 \(mn=\min A_i\),那么额外需要花费 \(mn(2i-N)\)。
所以当有 \(i\) 种商品使用优惠券时,总花费为 \(s-x+mn\max(0,2i-N)\)。
枚举 \(i\),取最小值即可。
如何想到
看到优惠券只能由“不使用优惠券购买商品”获得,可以先不考虑购买顺序,只考虑最后有多少种商品用券。
如果确定有 \(i\) 种商品使用优惠券,那么首先一定要把券给优惠最大的商品,也就是按照 \(A_i-B_i\) 从大到小选。
接下来只需要判断优惠券数量够不够。
不用券购买的商品有 \(N-i\) 个,因此能自然得到 \(N-i\) 张券,而需要使用 \(i\) 张。
所以缺少的优惠券数量就是 \(\max(0,i-(N-i))=\max(0,2i-N)\)。
而商品可以重复购买,所以缺券时只需要反复购买原价最小的商品,每次花费 \(mn\) 换一张券。
这样就可以直接枚举使用优惠券的商品数量。
代码
#include <bits/stdc++.h>
#define rep(i,j,k) for (int i = (j); i <= (k); i ++)
#define per(i,j,k) for (int i = (j); i >= (k); i --)
#define uint unsigned int
#define ll long long
#define ull unsigned long long
#define db double
#define ldb long double
#define mkp make_pair
#define eb emplace_back
#define e_ emplace
#define ls (p << 1)
#define rs (p << 1 | 1)
//#define int ll
using namespace std;
const int N = 2e5 + 5;
//const int MOD = 998244353;
//const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LINF = 4e18;
int T;
ll n, a, b, s, mn;
ll c[N];
signed main () {
//freopen (".in", "r", stdin);
//freopen (".out", "w", stdout);
ios::sync_with_stdio (0);
cin.tie (0);
cin >> T;
while (T --) {
cin >> n;
s = 0, mn = LINF;
rep (i, 1, n) {
cin >> a >> b;
s += a;
mn = min (mn, a);
c[i] = a - b;
}
sort (c + 1, c + 1 + n, greater<int> ());
ll ans = s, x = 0;
rep (i, 1, n) {
x += c[i];
ans = min (ans, s - x + mn * max (0LL, 2 * i - n));
}
cout << ans << '\n';
}
return 0;
}
复杂度
每组数据主要是排序。
时间复杂度为 \(O(N\log N)\)。
浙公网安备 33010602011771号