官方题解:[Algo Beat Contest 002.5 B] 草莓小蛋糕 (cakes)

· · 题解

这里是出题人的官方题解。

前言

“以后,或许不是永远。” “我们,总会有交集的。” ## 解题分析 ### 分析最优顺序 对于两种蛋糕 $i$ 和 $j$,我们需要确定谁应该先吃。 假设现在是第 $t$ 天,先吃 $i$ 再吃 $j$ 的总美味值为: $$(D_i - (t-1) \times X_i) + (D_j - t \times X_j)$$ 先吃 $j$ 再吃 $i$ 的总美味值为: $$(D_j - (t-1) \times X_j) + (D_i - t \times X_i)$$ 两者的差值为: $$(D_i - (t-1) \times X_i + D_j - t \times X_j) - (D_j - (t-1) \times X_j + D_i - t \times X_i)$$ $$= - (t-1) \times X_i - t \times X_j + (t-1) \times X_j + t \times X_i$$ $$= X_i - X_j$$ 因此得出结论: - 当 $X_i > X_j$ 时,先吃 $i$ 更优。 - 当 $X_i < X_j$ 时,先吃 $j$ 更优。 - 当 $X_i = X_j$ 时,先吃哪个无所谓。 所以将蛋糕按 $X_i$ 降序排列后的顺序是最优的。 ### 计算答案 我们考虑用初始时的总美味值减去因食物变质导致损失的美味值。 由于蛋糕数量可能很大,我们不能一天一天计算,需要批量处理同一种蛋糕。 对于第 $i$ 种蛋糕,假设从第 $s$ 天开始吃,连续吃 $C_i$ 天: - 第一天(第 $s$ 天)的损失的美味值为 $(s-1) \times X_i$。 - 最后一天(第 $s+C_i-1$ 天)的美味值为 $(s+C_i-2) \times X_i$。 这是一个等差数列,用首项加末项乘项数除以 $2$ 的求和公式进行计算即可。 注意使用 `__int128` 处理大整数。 ### 复杂度分析 - 时间复杂度:$O(N \log N)$,主要来自排序操作。 - 空间复杂度:$O(N)$,用于存储蛋糕信息。 ## 代码实现 ```cpp #include <bits/stdc++.h> using namespace std; #define ll long long #define i128 __int128 const ll N = 1e5 + 5; ll tc = 1, n, cur; i128 ans; void write(i128 x); struct cake { ll c, d, x; } a[N]; bool cmp(cake c1, cake c2) { return c1.x > c2.x; } i128 sum(i128 l, i128 r, i128 x) { return (l + r) * x / 2; } void solve() { scanf("%lld", &n); for (ll i = 1; i <= n; i++) { scanf("%lld %lld %lld", &a[i].c, &a[i].d, &a[i].x); i128 c = a[i].c, d = a[i].d; ans += c * d; } stable_sort(a + 1, a + n + 1, cmp); for (ll i = 1; i <= n; i++) { ll c = a[i].c, x = a[i].x; ans -= sum(cur * x, (cur + c - 1) * x, c); cur += c; } write(ans); } int main() { while (tc--) { solve(); } return 0; } void write(i128 x) { if (x < 0) { putchar('-'), x = -x; } if (x >= 10) { write(x / 10); } putchar('0' + x % 10); } ```