Dp的优化
Dp的优化
单调栈优化Dp
The Great Wall II
题意:
给你 n个点,问分成 1∼n 组,每一组的代价就是这一组中的最大值,问每一种情况的最小权值和。
思路:
把状态定义为 d i j 表示 走到 i 号点了 分了j 组的最小代价。
那么先枚举分成了几组 ,枚举从哪个点转移。
d[i][j]=min(d[i][j],d[k][j-1]+max(a[k+1]......a[i]));
这样的暴力的复杂度是 n^3的,考虑怎么优化。
首先 max(1 ~ j)这个肯定是单调递增的,然后如果碰到一个比较大的点,比前面的都大的情况的话,最优的转移肯定是找到前面
Code
const int N = 8100, mod = 1e9 + 7, INF = 1e10;
int lowbit(int x) { return x & -x; }
int gcd(int a, int b) { return a % b == 0 ? b : gcd(b, a % b); }
int a[N];
int d[N][2];//滚动数组。
int pre[N], mn[N];
// pre 代表当前的Dp值, mn代表 j-1中的 dp 的最小值
int stk[N];// 栈
// 走到 i 号点了 分了j 组的最小代价
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) d[i][1] = max(d[i - 1][1], a[i]);
//当前分成了 1组
cout << d[n][1] << endl;
for (int i = 2; i <= n; i++) {
int tt = 0;
pre[0] = INF;
for (int j = i; j <= n; j++) {
int temp = d[j - 1][(i - 1) & 1];//
// temp 相当于 如果不考虑 前面已经分好的组,一开始就是 前 j-1 个分成了 i-1 组
// 栈维护一个递增的序列保证,这一段区间的max 都是由 aj 主导
while (tt > 0 && a[stk[tt]] <= a[j]) temp = min(temp, mn[tt--]);
stk[++tt] = j;
mn[tt] = temp;// 当前的最小值
pre[tt] = min(pre[tt - 1], temp + a[j]);
// 可能 不在这个点 分成一个新的组 代价和比较小
// if (j == 2) cout << temp << " " << pre[tt] << endl;
d[j][i & 1] = pre[tt];// 更新
}
cout << d[n][i & 1] << endl;
}
}
signed main() {
kd;
int _;
_ = 1;
// cin>>_;
while (_--) solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!