0%

The 2026 ICPC Latin America Championship(2026 拉丁美洲决赛)-Gym-106416——D. Dropshipping(正过来看,ddl 是 ddl,也就是截止时间,但是反过来看,ddl 是激活时间)

题目大意

image

一开始对题面的理解有问题,我以为他可以保留折扣机会,但是实际上不行,不能保留。

题目描述

给定 NN 个顾客的商品购买需求,第 ii 个需求对应的商品价格为偶数 AiA_i

商店有一项优惠活动:每完成 XX 次全价购买后,下一次购买单件商品可以获得 50% 的折扣。此次打折购买不计入下一次获取折扣所需的 XX 次全价购买中。

你可以自由决定这 NN 件商品的购买顺序。但为了满足发货时间限制,第 ii 个需求对应的商品,必须在你的前 i+Ki+K 次购买中完成。

由于顾客已经提前支付了全额费用,你通过折扣节省下来的金额即为你个人的利润。请计算并输出你能获得的最大总利润(即所有打折购买商品原价的一半的总和)。

输入格式

第一行包含三个整数 NNXXKK1N,X2×1051 \le N, X \le 2 \times 10^50K2×1050 \le K \le 2 \times 10^5),分别表示需求数量、获得折扣所需的全价购买次数,以及延迟发货的限制参数。
第二行包含 NN 个偶数 A1,A2,,ANA_1, A_2, \dots, A_N2Ai1092 \le A_i \le 10^9),依次表示每个需求商品的价格。

输出格式

输出一个整数,表示你能获得的最大总利润。

样例 1

输入:

1
2
3 1 0
6 4 14

输出:

1
2

样例 1 解释

由于 K=0K=0,第 ii 个需求必须在第 ii 次购买时完成。因此购买顺序被严格固定为 [6, 4, 14]。只有第二次购买(价格为 44)可以享受半价折扣,能获得的最大利润为 4/2=24 / 2 = 2

样例 2

输入:

1
2
3 1 1
6 4 14

输出:

1
7

样例 2 解释

由于 K=1K=1,第 ii 个需求必须在前 i+1i+1 次购买内完成。合法的购买顺序包括 [6, 4, 14][6, 14, 4][4, 6, 14] 以及 [14, 6, 4]
其中,顺序 [6, 14, 4] 是最优的:在花费全价购买价格为 66 的商品后,可以对价格为 1414 的商品使用折扣,从而获得最大利润 14/2=714 / 2 = 7

思路讲解

呃,这个问他问的太早了。其实知道了,不能够保留这个折扣机会,那么其实倒过来看就非常 easy 的一件事情了

为什么反向处理呢?我们不难发现,一个数,更早被处理完全没有任何问题,但是不能更晚被处理

或者,可以这么说,正过来看,ddl 是 ddl,也就是截止时间,但是反过来看,ddl 是激活时间

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
ll gen_ans(const map<ll, vector<ll> > &ddl_price, ll N, ll X) {
ll ans = 0;
// gen_sorted_st(ddl_price, st1);
multiset<ll> st_small;
multiset<ll,greater<>> st_big;
// gen_sorted_st(ddl_price, st2);
for (int i = N; i >= 1; --i) {
auto it = ddl_price.find(i);
// 有没有 ddl 是 i 的商品?我们对其进行激活
if (it != ddl_price.end()) {
for (auto price: it->second) {
st_big.insert(price);
st_small.insert(price);
}
}
if (i % (X + 1) == 0) {
// 折扣的时候选择大的数字
ll add=*st_big.begin();
ans+=add/2;
st_erase(st_small,st_big,add);
} else {
// 平时抛弃小的数字
ll add=*st_small.begin();
st_erase(st_small,st_big,add);
}
}
return ans;
}

AC代码

AC
https://codeforces.com/gym/106416/submission/368218310

心路历程(WA,TLE,MLE……)