[HNOI2008] 玩具装箱
前言
终于进入新专题了家人们
列举一下还要补的专题
- 矩阵快速幂
- 组合数学
不过先不管了, 除了复习, 大部分时候总要向前看的嘛
考试的时候带着耳塞, 不带感觉好吵啊, 但是一直带着会神经衰弱的, 所以只能尝试集中注意力
思路
首先转化题意
给定
条线段, 第 条线段的长度为 , 我们要将这些线段分开, 其中一个分段 的花费为 , 求最小的花费之和
容易想到
容易找到转移
考虑最终的柿子
考虑
你发现
先不管
拆掉
套路的, 令
柿子转化为
考虑其性质满足
考虑实现,
由于
单调队列维护点即可
实现
框架#
直接按照上述内容实现即可
代码#
#include <bits/stdc++.h>
#define int long long
const int MAXN = 5e4 + 20;
int n, K;
int C[MAXN];
int dp[MAXN]; // 状态
int pre[MAXN], v[MAXN]; // 前缀和及其导出
namespace slope {
int X(int a) { return v[a]; }
int Y(int a) { return dp[a] + (v[a] + K) * (v[a] + K); }
int slope_up(int a, int b) { return Y(b) - Y(a); }
int slope_down(int a, int b) { return X(b) - X(a); }
} using namespace slope;
/*维护下凸包的单调队列*/
struct monoqueue {
std::deque<int> q;
bool checktail(int x) {
return slope_up(x, q.back()) * slope_down(q.back(), q.at(q.size() - 2)) <= slope_up(q.back(), q.at(q.size() - 2)) * slope_down(x, q.back());
}
/*找到当前斜率下最优的情况*/
int get(int k) {
/*弹出不满足下凸包性质的点*/ while (q.size() >= 2 && slope_up(q.front(), q.at(1)) <= k * slope_down(q.front(), q.at(1))) q.pop_front();
return q.front();
}
/*插入当前点*/
void insert(int x) {
/*弹出不满足下凸包性质的点*/ while (q.size() >= 2 && checktail(x)) q.pop_back();
q.push_back(x);
}
} mq;
signed main()
{
scanf("%lld %lld", &n, &K); K++;
for (int i = 1; i <= n; i++) scanf("%lld", &C[i]), pre[i] = pre[i - 1] + C[i], v[i] = pre[i] + i;
/*初始化*/
dp[0] = 0;
mq.insert(0);
for (int i = 1; i <= n; i++) {
int j = mq.get(2 * v[i]);
dp[i] = dp[j] + (i - j + pre[i] - pre[j] - K) * (i - j + pre[i] - pre[j] - K);
mq.insert(i);
}
printf("%lld", dp[n]);
return 0;
}
总结
常见的
优化不来可以考虑继续研究柿子
常见的斜率优化, 拆柿子能力史诗级提升
vivo 50
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】