Codeforces#721 E

题目链接

  题意:将一个序列分成k段,求出这k段中cost(t)=xset(t)last(x)first(x)的大小,也就是求出区间内最后一次出现的数和第一次出现的数之间的差值。
  思路:
  对于求解这个式子的最小值,考虑用dp来求解,dp[i][j]表示在下标为j的位置之前分成了i段,从而有了dp[i][j]=mink<j{dp[[i1][k]+w[k+1][j]},如果暴力的去求解这个式子的话会因为后面w[k+1][j]这个式子超时,所以重点就是要优化这个式子。
  last(x)first(x)可以拆成last(x)prev(x)+(prev(x)first(x)),也就是我们去求这个式子的时候可以用前缀和的操作来进行优化。而每一次求解min的操作的时候,同时需要找到区间最小值来是的前缀和最小,那么就可以考虑用线段树来维护。

int n, m; std::cin >> n >> m; std::vector<int> pre(n + 1), last(n + 1), a(n + 1); for (int i = 1; i <= n; i++ ) { std::cin >> a[i]; last[i] = pre[a[i]]; pre[a[i]] = i; } std::vector<int> dp(n + 1, 2E9); dp[0] = 0; for (int i = 0; i < m; i ++ ) { Seg SGT(n + 1); for (int i = 0; i <= n; i++ ) { SGT.change(1, 0, n, i, i, dp[i]); } for (int i = 1; i <= n; i++ ) { if (last[i]) SGT.change(1, 0, n, 0, last[i] - 1, i - last[i]); dp[i] = SGT.query(1, 0, n, 0, i - 1); } } std::cout << dp[n] << "\n";

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16581424.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示