题目:

洛谷3648

注:这道题洛谷3648有SPJ,要求输出方案。BZOJ3675数据组数较多但不要求输出方案。

分析:

这可能是我第三次重学斜率优化了……好菜啊

这道题首先一看就是个DP。稍微推一推类似下面这种式子就会发现事实上结果和切的顺序无关

\[a(b+c)+bc=ab+c(a+b)=ab+ac+bc
\]

那么就可以用\(f[i][j]\)表示切了\(j\)次,最右一次在\(i\)后面切的最大值。用\(sum[i]\)表示原序列前\(i\)个数之和,那么就有了这个DP方程(假设在\(i\)后面是第一次切割):

\[f[i][j]=max(f[k][j-1]+sum[k]\times (sum[i]-sum[k]))(0<k<i)
\]

其中\(j\)这一维可以滚动存储。转移的时候顺便记一下从什么地方转移过来就行。这个时间复杂度是\(O(n^2k)\)。丢一部分代码。

  1. int work()
  2. {
  3. read(n), read(k);
  4. for (int i = 1; i <= n; i++)
  5. read(sum[i]), sum[i] += sum[i - 1];
  6. for (int i = 2; i <= k; i++)
  7. for (int j = n; j > 0; j--)
  8. for (int g = 1; g < j; g++)
  9. {
  10. if (dp[j] < dp[g] + sum[g] * (sum[j] - sum[g]))
  11. {
  12. dp[j] = dp[g] + sum[g] * (sum[j] - sum[g]);
  13. pre[i][j] = g;
  14. }
  15. }
  16. int st = 0;
  17. ll ans = 0;
  18. for (int i = 1; i <= n; i++)
  19. if (ans < dp[i] + sum[i] * (sum[n] - sum[i]))
  20. {
  21. ans = dp[i] + sum[i] * (sum[n] - sum[i]);
  22. st = i;
  23. }
  24. write(ans), putchar('\n'), write(st);
  25. for (int i = k; i > 1; i--)
  26. putchar(' '), write(st = pre[i][st]);
  27. return 0;
  28. }

实测洛谷上有\(64\)分。64分够了,本文结束。

考虑斜率优化。以下的讨论均为在\(j\)(切的次数)固定的情况下,为方便说明,用\(f[i]\)表示\(f[i][j]\),\(g[i]\)表示\(f[i][j-1]\)。再来看这个式子。

\[f[i]=max(g[j]+sum[j]\times (sum[i]-sum[j]))(0<j<i)
\]

考虑对于\(g[j]\)和\(g[k](j<k<i)\),如果从\(g[j]\)转移到\(f[i]\)比从\(g[k]\)转移更优,那么一定满足:

\[g[j]+sum[j]\times (sum[i]-sum[j])>g[k]+sum[k]\times (sum[i]-sum[k])
\]

进行一些变换,得到:

\[g[j]-sum[j]^2>g[k]-sum[k]^2+sum[i]\times (-sum[j]+sum[k])
\]

由于前缀和单调不降,\((-sum[j]+sum[k])\)是非负的,除到右边得到(暂时不考虑为\(-sum[j]+sum[k]=0\)的特殊情况):

\[\frac{(g[j]-sum[j]^2)-(g[k]-sum[k]^2)}{-sum[j]+sum[k]}>sum[i]
\]

可以看出左侧的式子很“工整”。把\(g[j]-sum[j]^2\)看作点\(j\)的纵坐标,\(-sum[j]\)看作点\(j\)的横坐标,则左侧就是\(j\)和\(k\)两点之间的斜率。对于横坐标相等的两点,斜率根据纵坐标的符号视作正无穷或负无穷。

接下来阅读前,请时刻牢记:对于\(j<k<i\),如果\(j\)和\(k\)之间的斜率大于\(sum[i]\),则\(j\)比\(k\)优

同时还有这句话的反面:对于\(j<k<i\),如果\(j\)和\(k\)之间的斜率不大于\(sum[i]\),则\(j\)比\(k\)劣

由于\(sum[i]\)是单调不降的,所以满足决策单调性,即:如果对于\(f[i]\),从\(g[k]\)转移比从\(g[j]\)优\((j<k)\),则对于\(f[i'](i<i'\leq n)\),\(g[j]\)不可能是最优的(显然,\(j\)和\(k\)间的斜率是不受\(i\)影响的,而如果此时斜率已经小于等于\(sum[i]\)了,则以后也不可能大于\(sum[i]\),所以\(j\)以后永远不可能比\(k\)优) 。

那么可以维护一个斜率递增的单调队列。如果感到这部分难以理解,请再反复看上面三句加粗的话。当决策\(f[i]\)时,弹出单调队列首的若干元素,直到只剩一个元素或前两个元素的斜率大于\(sum[i]\)。当尝试插入\(i\)点时,弹出队尾的若干元素,直到只剩一个元素或队尾与\(i\)的斜率比队尾后两个元素大。在几何意义上,这是一个下凸包。读者可以画图理解。

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cctype>
  4. #include <cstring>
  5. using namespace std;
  6. namespace zyt
  7. {
  8. template<typename T>
  9. inline void read(T &x)
  10. {
  11. bool f = false;
  12. char c;
  13. x = 0;
  14. do
  15. c = getchar();
  16. while (c != '-' && !isdigit(c));
  17. if (c == '-')
  18. f = true, c = getchar();
  19. do
  20. x = x * 10 + c - '0', c = getchar();
  21. while (isdigit(c));
  22. if (f)
  23. x = -x;
  24. }
  25. template<typename T>
  26. inline void write(T x)
  27. {
  28. static char buf[20];
  29. char *pos = buf;
  30. if (x < 0)
  31. putchar('-'), x = -x;
  32. do
  33. *pos++ = x % 10 + '0';
  34. while (x /= 10);
  35. while (pos > buf)
  36. putchar(*--pos);
  37. }
  38. typedef long long ll;
  39. typedef long double ld;
  40. const int N = 1e5 + 10, K = 210;
  41. const ll LINF = 0x3f3f3f3f3f3f3f3fLL;
  42. int n, k, now;
  43. ll sum[N], dp[2][N];
  44. int pre[K][N];
  45. inline ll sq(const ll x)
  46. {
  47. return x * x;
  48. }
  49. inline ll y(const int i)
  50. {
  51. return dp[now ^ 1][i] - sq(sum[i]);
  52. }
  53. inline ll x(const int i)
  54. {
  55. return -sum[i];
  56. }
  57. inline ld ratio(const int i, const int j)
  58. {
  59. if (x(i) == x(j))
  60. return (y(i) - y(j) > 0) ? LINF : -LINF;
  61. else
  62. return (ld)(y(i) - y(j)) / (x(i) - x(j));
  63. }
  64. int work()
  65. {
  66. static int q[N];
  67. read(n), read(k);
  68. for (int i = 1; i <= n; i++)
  69. read(sum[i]), sum[i] += sum[i - 1];
  70. for (int i = 2; i <= k; i++)
  71. {
  72. now = i & 1;
  73. int h = 0, t = 1;
  74. q[0] = 0;
  75. for (int j = 1; j <= n; j++)
  76. {
  77. while (h + 1 < t && ratio(q[h], q[h + 1]) <= sum[j])
  78. ++h;
  79. dp[now][j] = dp[now ^ 1][q[h]] + sum[q[h]] * (sum[j] - sum[q[h]]);
  80. pre[i][j] = q[h];
  81. while (h + 1 < t && ratio(q[t - 2], q[t - 1]) >= ratio(q[t - 1], j))
  82. --t;
  83. q[t++] = j;
  84. }
  85. }
  86. int st = 0;
  87. ll ans = 0;
  88. for (int i = 1; i <= n; i++)
  89. if (ans < dp[now][i] + sum[i] * (sum[n] - sum[i]))
  90. {
  91. ans = dp[now][i] + sum[i] * (sum[n] - sum[i]);
  92. st = i;
  93. }
  94. write(ans), putchar('\n'), write(st);
  95. for (int i = k; i > 1; i--)
  96. putchar(' '), write(st = pre[i][st]);
  97. return 0;
  98. }
  99. }
  100. int main()
  101. {
  102. return zyt::work();
  103. }

【洛谷3648/BZOJ3675】[APIO2014]序列分割(斜率优化DP)的更多相关文章

  1. bzoj3675[Apio2014]序列分割 斜率优化dp

    3675: [Apio2014]序列分割 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 3508  Solved: 1402[Submit][Stat ...

  2. 【洛谷3648】[APIO2014] 序列分割(斜率优化DP)

    点此看题面 大致题意: 你可以对一个序列进行\(k\)次分割,每次得分为两个块元素和的乘积,求总得分的最大值. 区间\(DPor\)斜率优化\(DP\) 这题目第一眼看上去感觉很明显是区间\(DP\) ...

  3. 【bzoj3675】[Apio2014]序列分割 斜率优化dp

    原文地址:http://www.cnblogs.com/GXZlegend/p/6835179.html 题目描述 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列 ...

  4. [APIO2014]序列分割 --- 斜率优化DP

    [APIO2014]序列分割 题目大意: 你正在玩一个关于长度为\(n\)的非负整数序列的游戏.这个游戏中你需要把序列分成\(k+1\)个非空的块.为了得到\(k+1\)块,你需要重复下面的操作\(k ...

  5. BZOJ3675: [Apio2014]序列分割(斜率优化)

    Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 4186  Solved: 1629[Submit][Status][Discuss] Descript ...

  6. BZOJ 3675 [Apio2014]序列分割 (斜率优化DP)

    洛谷传送门 题目大意:让你把序列切割k次,每次切割你能获得 这一整块两侧数字和的乘积 的分数,求最大的分数并输出切割方案 神题= = 搞了半天也没有想到切割顺序竟然和答案无关...我太弱了 证明很简单 ...

  7. 洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP

    洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他. 玩具上有一个数列,数列中某些项的值可能会 ...

  8. P3648 [APIO2014]序列分割 斜率优化

    题解:斜率优化\(DP\) 提交:\(2\)次(特意没开\(long\ long\),然后就死了) 题解: 好的先把自己的式子推了出来: 朴素: 定义\(f[i][j]\)表示前\(i\)个数进行\( ...

  9. BZOJ 3675 APIO2014 序列切割 斜率优化DP

    题意:链接 方法:斜率优化DP 解析:这题BZ的数据我也是跪了,特意去网上找到当年的数据后面二十个最大的点都过了.就是过不了BZ. 看到这道题自己第一发DP是这么推得: 设f[i][j]是第j次分第i ...

  10. 【洛谷 P3648】 [APIO2014]序列分割 (斜率优化)

    题目链接 假设有\(3\)段\(a,b,c\) 先切\(ab\)和先切\(bc\)的价值分别为 \(a(b+c)+bc=ab+bc+ac\) \((a+b)c+ab=ab+bc+ac\) 归纳一下可以 ...

随机推荐

  1. buf.writeUInt32BE()

    buf.writeUInt32BE(value, offset[, noAssert]) buf.writeUInt32LE(value, offset[, noAssert]) value {Num ...

  2. codeforces round #394 (div. 2) A\B 题解

    开始啦~ 始まった T1 #include <stdio.h> int l,r,even,odd; void Jud(){ for(int i=1;i<=200;i++){ for( ...

  3. Python网络编程—socket(二)

    http://www.cnblogs.com/phennry/p/5645369.html 接着上篇博客我们继续介绍socket网络编程,今天主要介绍的内容:IO多路复用.多线程.补充知识点. 一.I ...

  4. Android BottomSheet:以选取图片为例(2)

     Android BottomSheet:以选取图片为例(2) 附录文章5简单介绍了常见的分享面板在BottomSheet中的具体应用.本文再以常见的选取图片为例写一个例子. 布局文件: < ...

  5. Mongodb慢查询笔记 (Mongodb slow query log)

    -- =========================== -- mongodb slow query log -- =========================== Reference: h ...

  6. SVN提交时报错:Commit blocked by pre-commit hook (exit code 1) with no output.

    可能的原因: 提交代码的SVN命令中,Comment长度短了.参考:http://tortoisesvn.net/docs/nightly/TortoiseSVN_en/tsvn-howto-minl ...

  7. Swift具体解释之六----------------枚举、结构体、类

    枚举.结构体.类 注:本文为作者自己总结.过于基础的就不再赘述 ,都是亲自測试的结果.如有错误或者遗漏的地方.欢迎指正,一起学习. 1.枚举 枚举是用来定义一组通用类型的一组相关值 ,关键字enum ...

  8. python supervisor进程监控工具的使用

    supervisor —— a process control system 另外一个类似 supervisor的工具,因为supervisor 不兼容python3, !!! Circus Proc ...

  9. How to Use DHCP Relay over LAN? - DrayTek Corp

    Assuming Vigor2960 has two LAN networks. Network Administrator wants that, when the internal DHCP is ...

  10. 《天龙八部》及Ogre3D模型的3ds max导入插件(源码公布)

    測试UE4项目.苦于没有像样的模型和动画资源,所以想到把<天龙八部>等网游的资源导出来用. 于是做了个max导入插件. 效果还是不错的. 效果图: 上图是<斗破苍穹>的游戏资源 ...