传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4518

首先推式子,我们用$x_i$表示第$i$段的路程,$sum$表示总路程,根据方差和平均数的定义,有:

$ \Large sum = \sum\limits_{i=1}^{m}{x_i} \\ $
$ \Large \bar{x} = \frac{sum}{m} \\ $
$ \Large ans = \frac{ \sum\limits_{i=1}^{m}{ (x_i - \bar{x})^2 } }{m} \cdot m^2 \\ $

然后我们把式子展开化简一番,就有了:

$ \Large ans = ( \sum\limits_{i=1}^{m}{ (x_i - \frac{sum}{m})^2 } ) \cdot m \\ $
$ \Large ans = ( \sum\limits_{i=1}^{m}{ \frac{ (m \cdot x_i - sum)^2 }{m^2} } ) \cdot m \\ $
$ \Large ans = \sum\limits_{i=1}^{m}{ \frac{ m^2 \cdot x_i^2 - 2 \cdot m \cdot x_i \cdot sum + sum^2 }{m} } \\ $
$ \Large ans = sum^2 + \sum\limits_{i=1}^{m}{ (m \cdot x_i^2 - 2 \cdot x_i \cdot sum) } \\ $

于是我们的目标就是最小化这个式子,看上去很像个dp?没错。

先抛开前面的常数$sum^2$,我们下面的dp过程中计算的是后面那个求和式子的最小值。

设$f(i,j)$表示我们把前$j$个数划分成了$i$段的最小值,$dist(i,j)$表示从第$i$个数到第$j$个数的和,用$d$数组存放前缀和,于是有:

$ \Large dist(i,j) = d_j - d_{i-1} \\ $
$ \Large f(i,j) = f(i-1,k) + m \cdot dist(k+1,j)^2 - 2 \cdot dist(k+1,j) \cdot sum \\ $

对这个式子展开并化简,得到:

$ \Large f(i,j) = f(i-1,k) + m \cdot (d_j - d_k)^2 - 2 \cdot (d_j - d_k) \cdot sum \\ $
$ \Large f(i,j) = f(i-1,k) + m \cdot (d_j^2 - 2 \cdot d_j \cdot d_k + d_k^2 ) - 2 \cdot d_j \cdot sum + 2 \cdot d_k \cdot sum \\ $

再整理一下式子,我们就可以进行斜率优化dp了,下面的$x$和$y$表示状态对应的点的横纵坐标,$k$表示状态对应的斜率,$b$表示状态对应的常数项。

$ \Large b = m \cdot d_j^2 - 2 \cdot d_j \cdot sum \\ $
$ \Large y = f(i-1,k) + m \cdot d_k^2 + 2 \cdot d_k \cdot sum \\ $
$ \Large x = d_k \\ $
$ \Large k = 2 \cdot m \cdot d_j \\ $
$ \Large f(i,j) = y - x \cdot k + b \\ $

我们的任务是最小化$f(i,j)$,且$x,y,k$是递增的,于是就用单调队列维护一个下凸壳就好啦。

代码:

 #include <cstring>
#include <cstdio>
#include <algorithm> using namespace std;
typedef long long ll;
const double EPS = 1e-;
const int MAXN = ; struct Point {
ll x, y;
Point( ll x = , ll y = ):x(x),y(y){}
Point operator-( const Point &rhs ) const {
return Point(x-rhs.x, y-rhs.y);
}
};
typedef Point Vector;
double Cross( Vector v, Vector w ) {
return (double)v.x*w.y - (double)v.y*w.x;
} namespace MonoQ { // 维护下凸壳的单调队列
Point P[MAXN];
int head, tail;
void clear() {
head = tail = ;
}
void insert( Point Q ) { // 插入一个点
while( tail-head >= && Cross(P[tail-]-P[tail-], Q-P[tail-]) < EPS ) --tail;
P[tail++] = Q;
}
Point query( ll k ) { // 根据斜率查询最小值
while( tail-head >= && P[head].y - P[head].x*k > P[head+].y - P[head+].x*k ) ++head;
return P[head];
}
} ll n, m, d[MAXN] = {}; ll f[][MAXN];
ll getx( int i ) { // 这四个函数用于获取一个状态对应的几何信息
return d[i];
}
ll gety( int cur, int i ) {
return f[cur][i] + m*d[i]*d[i] + *d[i]*d[n];
}
ll getb( int i ) {
return m*d[i]*d[i] - *d[i]*d[n];
}
ll getk( int i ) {
return *m*d[i];
}
void solve() {
int cur = ;
memset( f, 0x3f, sizeof(f) );
f[cur][] = ;
for( int i = ; i <= m; ++i ) {
cur ^= ;
MonoQ::clear();
MonoQ::insert( Point(getx(i-), gety(cur^, i-)) );
for( int j = i; j <= n; ++j ) {
Point P = MonoQ::query(getk(j));
f[cur][j] = P.y - P.x*getk(j) + getb(j);
MonoQ::insert( Point(getx(j), gety(cur^, j)) );
}
}
printf( "%lld\n", f[cur][n] + d[n]*d[n] ); // 别忘了最后加上sum^2
} int main() {
scanf( "%lld%lld", &n, &m );
for( int i = ; i <= n; ++i ) {
scanf( "%lld", d+i );
d[i] += d[i-]; // 前缀和
}
solve();
return ;
}

【题解】征途 SDOI 2016 BZOJ 4518的更多相关文章

  1. 【BZOJ 4518】【SDOI 2016 Round1 Day2 T3】征途

    比较明显的斜率优化DP,省选时因为时间太紧张和斜率DP写得不熟等原因只写了60分的暴力DP,其实当时完全可以对拍来检验标算的正确,但是我当时too naive- 很快打完了,调了将近一晚上QAQ,因为 ...

  2. 征途 bzoj 4518

    征途(1s 256MB)journey [问题描述] Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地.除第m天外,每一天 ...

  3. 【BZOJ 4598】【SDOI 2016 Round2 Day1 T3】模式字符串

    2016-05-21因为BZOJ上“ 数据文件太过巨大,仅提供前三组数据测试.”所以我考场上写的60分的点分治交上去也A了. 我的这个点分治的时间复杂度是$O(Tnmlogn)$的,听题解时没听懂$O ...

  4. 【BZOJ 4517】【SDOI 2016 Round1 Day2 T2】排列计数

    本蒟蒻第一次没看题解A的题竟然是省选$Round1$ $Day2$ $T2$ 这道组合数学题. 考试时一开始以为是莫队,后来想到自己不会组合数的一些公式,便弃疗了去做第三题,,, 做完第三题后再回来看 ...

  5. 动态规划(决策单调优化):BZOJ 4518 [Sdoi2016]征途

    4518: [Sdoi2016]征途 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 532  Solved: 337[Submit][Status][ ...

  6. BZOJ 4518 [Sdoi2016]征途(分治DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4518 [题目大意] 给出一个数列,分成m段,求方差最小,答案乘上m的平方. [题解] ...

  7. BZOJ 4518: [Sdoi2016]征途 [斜率优化DP]

    4518: [Sdoi2016]征途 题意:\(n\le 3000\)个数分成m组,一组的和为一个数,求最小方差\(*m^2\) DP方程随便写\(f[i][j]=min\{f[k][j-1]+(s[ ...

  8. ●BZOJ 4518 [Sdoi2016]征途

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4518 题解: 斜率优化DP 首先看看最后答案的形式: 设a[i]为第i天走的距离,那么 $A ...

  9. bzoj 4518: [Sdoi2016]征途

    Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地.除第m天外,每一天晚上Pine都必须在休息站过夜 ...

随机推荐

  1. 阿里巴巴将在美国推出电子商务网站11 Main

    新浪科技讯 北京时间2月11日晚间消息,阿里巴巴集团周二向路透社证实,阿里巴巴将通过旗下子公司Vendio和Auctiva在美国推出一个电子商务网站. 该网站的名称为“11 Main”(11main. ...

  2. Windows下使用WinRAR命令自动备份文件

    最近有一个需求:为了防止数据丢失,每天对固定文件夹下的文件进行打包压缩备份. 解决办法:使用Windows的任务计划程序,每天执行一下压缩命令: Windows任务计划程序在这里就不再介绍了,网上有很 ...

  3. Python 代码调试技巧

    使用 pdb 进行调试 pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点.单步调试.进入函数调试.查看当前代码.查看栈片段.动态改变变 ...

  4. 用 Python 3 的 async / await 做异步编程

    前年我曾写过一篇<初探 Python 3 的异步 IO 编程>,当时只是初步接触了一下 yield from 语法和 asyncio 标准库.前些日子我在 V2EX 看到一篇<为什么 ...

  5. python 读取blob

    for num in range(76802): # if num == 0: # c[num] = imagedata[0:4] # d[num] = struct.unpack('i', c[nu ...

  6. mysql 设置远程登录

    1.本机登录进mysql,并切换到本机mysql数据库下 2. GRANT ALL PRIVILEGES ON *.* TO 'tigase'@'%' IDENTIFIED BY '123456' W ...

  7. HDU 5642 King's Order dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5642 King's Order  Accepts: 381  Submissions: 1361   ...

  8. lintcode-389-判断数独是否合法

    389-判断数独是否合法 请判定一个数独是否有效. 该数独可能只填充了部分数字,其中缺少的数字用 . 表示. 注意事项 一个合法的数独(仅部分填充)并不一定是可解的.我们仅需使填充的空格有效即可. 说 ...

  9. 对mysql联合索引中的字段进行合理排序

    在MySQL的where条件中,有时会用到很多的条件,通常为了加快速度会把这些字段放到联合索引中,可以更快的提高搜索速度: 但是对联合索引中字段顺序的合理排序,便更能提高速度 例子:select * ...

  10. Mybatis 映射关系

    相比 Hibernate,Mybatis 的映射关系就显得简单了很多. 未完待续....