【ybt金牌导航1-3-3】【luogu P4072】征途

征途

题目链接:ybt金牌导航1-3-3 / luogu P4072

题目大意

有 n 个值,你要把它划分成 m 段,使得把每段的值加起来得到段的值,段值的方差最小。
输出这个最小方差乘 m^2,可证明这个是整数。

思路

.首先我们考虑化简式子:(设分段之后每一段的长度是 dix¯ 是它们的平均值,即 x¯=i=1mdim
s2×m2
=i=1m(dix¯)2m×m2
=i=1m(dix¯)2×m
=i=1m(di22×di×x¯+x¯2)×m
=m×i=1mdi2+i=1m(2×di×i=1mdim+(i=1mdim)2)×m
=m×i=1mdi2+i=1m(2×di×i=1mdi+(i=1mdim)(i=1mdi))

我们再弄一个 sum=i=1mdi
=m×i=1mdi2+i=1m(2×di×sum+(summ)×sum)
=m×i=1mdi2+(2)×i=1mdi×sum+i=1m(1m)×sum2
=m×i=1mdi2+(2)×sum×sum+sum2
=m×i=1mdi22×sum2+sum2
=m×i=1mdi2sum2

那你会发现,你就是要让 i=1mdi2 最小。

那你可以设 fi,j 为前 i 个数划分成了 j 段的最小值。
那会有这个方程:fi,j=mink=1i1{fk,j1+(sisk)2}

那可以看出它是有单调性的,那我们就直接上分治,做就好了。

代码

#include<cstdio> #include<iostream> #define ll long long using namespace std; int n, m; ll a[3001], s[3001], f[3001][3001]; void slove(int op, int l, int r, int L, int R) {//分治 int mid = (l + r) >> 1, pl = 0; ll minn = 1e15; for (int i = L; i <= R && i < mid; i++) {//对于处理范围中间的点用枚举答案范围求答案 ll now = f[i][op - 1] + (s[mid] - s[i]) * (s[mid] - s[i]); if (now < minn) { pl = i; minn = now; } } f[mid][op] = minn; if (l < mid) slove(op, l, mid - 1, L, pl); if (mid < r) slove(op, mid + 1, r, pl, R); } int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); s[i] = s[i - 1] + a[i]; } for (int i = 1; i <= n; i++)//预处理只有一段的 f[i][1] = s[i] * s[i]; for (int i = 2; i <= m; i++) slove(i, 1, n, 1, n); printf("%lld", f[n][m] * m - s[n] * s[n]);//记得套回公式里 return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_1-3-3.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(23)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示