|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
自学一下斜率优化,有一定的理解难度,我理了好久思路
P2356 任务安排
- // 易推出 dp 式: dp[i] = dp[j] + (sumc[i] - sumc[j]) * sumt[i] + s * (sumc[n] - sumc[j])
- // dp[j] = (s + sumt[i]) * sumc[j] + dp[i] - sumc[i] * sumt[i] - s * sumc[n]
- // 转化为一次函数形式 y = k * x + b, y 为 dp[j], k 为(s + sumt[i]), x 为 sumc[i], 其余为 b
- // 那么题意转化为 ---> 求 b 的最小值 ---> 求直线 y 的最小截距
- // 对于所有已知点(sumc[j], dp[j]), y 的 k 固定, y 的最小截距就是直线 y 向上平移第一个碰到的点产生的截距
- // 因此维护一个下凸包即可, 即维护 (dp[i] - dp[j]) / (sumc[i] - sumc[j]) >= k 这么一个不等式,由于其的单调性易联想到单调队列
- // 由于 t 可以为负数,因此 k 不一定单调递增,但是我们维护的 (dp[i] - dp[j]) / (sumc[i] - sumc[j]) 具有单调性,因此二分跳跃至正确决策点即可
- // Created on 2025/8/10 20:37.
- #include <bits/stdc++.h>
- #define int long long
- #define rep(i, j, k) for(int i = j; i <= k; i++)
- #define reps(i, j, k) for(int i = j; i >= k; i--)
- using namespace std;
- const int _ = 3e5 + 7;
- int n, s, c[_], t[_], f[_], st[_], l = 0, r = 0;
- int x(int a, int b){
- return c[b] - c[st[a]];
- }
- int y(int a, int b){
- return f[b] - f[st[a]];
- }
- int get_pos(int i){
- int k1 = l, k3 = r, k = t[i] + s;
- while (k1 < k3){
- int k2 = (k1 + k3) >> 1;
- if (y(k2, st[k2 + 1]) >= x(k2, st[k2 + 1]) * k) k3 = k2;
- else k1 = k2 + 1;
- }
- return k1;
- }
- signed main() {
- ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
- cin >> n >> s;
- rep(i, 1, n){
- cin >> t[i] >> c[i];
- t[i] += t[i - 1], c[i] += c[i - 1];
- }
- rep(i, 1, n){
- int pos = st[get_pos(i)];
- f[i] = f[pos] + (c[i] - c[pos]) * t[i] + s * (c[n] - c[pos]);
- while (l < r && y(r - 1, st[r]) * x(r, i) >= y(r, i) * x(r - 1, st[r])) r--;
- st[++r] = i;
- }
- cout << f[n];
- return 0;
- }
复制代码
小小记录一下做的紫题,属于是很大进步了, 个人感觉这题从代码角度比 严格次小生成树 简单很多, 但是思想上难不少,考场还是喜欢 严格次小生成树 这类题目一点 |
|