博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
征途 BZOJ 4518
阅读量:4608 次
发布时间:2019-06-09

本文共 2534 字,大约阅读时间需要 8 分钟。

征途

【问题描述】

Pine开始了从S地到T地的征途。

从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。

Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。

Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。

帮助Pine求出最小方差是多少。

设方差是v,可以证明,v×m^2是一个整数。为了避免精度误差,输出结果时输出v×m^2。

【输入格式】

第一行两个数 n、m。

第二行 n 个数,表示 n 段路的长度

【输出格式】

 一个数,最小方差乘以 m^2 后的

【样例输入】

5 2
1 2 5 8 6

【样例输出】

36

【数据范围】

1≤n≤3000,保证从 S 到 T 的总路程不超过 30000


题解:

来推一下式子:

方差:(x1 - aver)2 + (x2 - aver)+ ... + (xm - aver)2  / m

然后题意要求乘m2

那么

 m×[(x1 - aver)2 + (x2 - aver)+ ... + (xm - aver)]

= m×[x12 + x22 + ... + xm2 - 2aver(x+ x2 + ... + xm ) + m × aver2]

= m×(x12 + x22 + ... + xm2) - 2sum+ sum2  (aver = sum / m)

= m×(x12 + x22 + ... + xm2) - sum

其实m和sum都为常量,那么只要考虑中间的平方和部分

设f[i][j]为分到点j且分成i段时每一段的平方和

转移方程即为:f[i][j] = min(f[i][j], f[i - 1][k] + (sum[j] - sum[k]) * (sum[j] - sum[k])); (k < j)

三方效率肯定过不了,看出这是一个斜率优化的裸题,那就可以虾搞蛋了~\(≧▽≦)/~

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 using namespace std; 8 inline int Get() 9 {10 int x = 0;11 char c = getchar();12 while('0' > c || c > '9') c = getchar();13 while('0' <= c && c <= '9')14 {15 x = (x << 3) + (x << 1) + c - '0';16 c = getchar();17 }18 return x;19 }20 int n, m;21 int t, w;22 int c[10233];23 int s[10233];24 long long aver;25 long long f[3233][3233];26 long long sum[10233];27 double Up(int x, int y, int i)28 {29 return f[i - 1][x] + sum[x] * sum[x] - f[i - 1][y] - sum[y] * sum[y];30 }31 double Down(int x, int y)32 {33 return (sum[x] - sum[y]) << 1;34 }35 long long Dp(int i, int j, int x)36 {37 return f[i - 1][x] + (sum[j] - sum[x]) * (sum[j] - sum[x]);38 }39 int main()40 {41 scanf("%d%d", &n, &m);42 for(int i = 1; i <= m; ++i)43 for(int j = 1; j <= n; ++j)44 f[i][j] = 214748364721474836LL;45 for(int i = 1; i <= n; ++i)46 {47 scanf("%d", &c[i]);48 sum[i] = sum[i - 1] + c[i];49 f[1][i] = sum[i] * sum[i];50 }51 aver = sum[n];52 for(int i = 2; i <= m; ++i)53 {54 t = 1, w = 0;55 s[++w] = i - 1;56 for(int j = i; j <= n; ++j)57 {58 /* 59 for(int k = i - 1; k <= j; ++k)60 f[i][j] = min(f[i][j], f[i - 1][k] + (sum[j] - sum[k]) * (sum[j] - sum[k]));61 */62 while(t < w && Up(s[t], s[t + 1], i) / Down(s[t], s[t + 1]) <= sum[j]) ++t;63 f[i][j] = Dp(i, j, s[t]);64 while(t < w && Up(j, s[w], i) / Down(j, s[w]) <= Up(s[w], s[w - 1], i) / Down(s[w], s[w - 1])) --w;65 s[++w] = j;66 }67 }68 printf("%lld", (long long) m * f[m][n] - aver * aver);69 }

转载于:https://www.cnblogs.com/lytccc/p/6248001.html

你可能感兴趣的文章
[编写高质量代码:改善java程序的151个建议]建议67 不同的列表选择不同的遍历方法...
查看>>
整合SSM遇到的错误,数据库连接失败问题集合
查看>>
对象的比较与排序:IComparable和IComparer接口
查看>>
回望之二:游园10首
查看>>
智慧解析第08课:《战国策》中的心理学
查看>>
[C#] Helper 的封装 -- RandomHelper
查看>>
原型和原型链
查看>>
数据的增量更新之EXISTS
查看>>
【BIRT】交叉报表中出现空值设置为默认值
查看>>
Log4js 工作原理及代码简析
查看>>
windows phone 设置image 的source
查看>>
Personalized serious capabilities from the
查看>>
在ubuntu上部署Django
查看>>
android分享软件功能的实现
查看>>
数据库表设计工具
查看>>
E - The Blocks Problem ( UVA - 101)
查看>>
28个你不知道的HTML5的新技巧
查看>>
Oracle文档
查看>>
iOS开发中获取WiFi相关信息
查看>>
Ionic2:创建App启动页滑动欢迎界面
查看>>