首先看这样一个问题:
洛谷 P3195 [HNOI2008]玩具装箱
题目大意:
有 \(n\) 个物品排成一行,第 \(i\) 个物品权值为 \(C_i\) ,现要求将这些物品分成若干段,每段的花费为 \(((\sum_{i=l}^{r}{C_i})-L)^2\) (其中 \(l\),\(r\) 为这一段的左右端点, \(L\) 为给定常数),问最小的总花费.保证 \(1 \leq n \leq 5 \times 10^4\),\(1 \leq L \leq 10^7\),\(1 \leq C_i \leq 10^7\) .
这题显然是一道 DP 题. 令 \(dp_{i}\) 为考虑前 \(i\) 个物品的最小代价, \(sum_i=\sum_{j=1}^{i}C_j\) , 可以想出这样的状态转移方程:
然而, 如果暴力转移时间复杂度是 \(\Theta(n^2)\) 的, 显然会T, 有什么办法优化吗?
动态规划优化的一个重要思路是把可能决策的范围缩小 (即排除不可能的决策) . 顺着这个思路试试看?
首先我们观察状态转移方程, 发现这个 \(\min\) 函数很碍事, 把它去掉:
这个方程太长了, 所以考虑令 \(a_i=sum_i-L\) , \(b_i=sum_i\) , 代入得:
这个平方也很碍事, 把它展开:
把跟 \(i\) 有关的移到等号一边, 跟 \(j\) (读作"勾") 有关的放到另一边:
......感觉直到现在我们做的都是一些很常规的操作...... 但是如果我们放一个直线的表达式跟它对比一下?
| \((2a_i)b_j+(dp_i-{a_i}^2)=(dp_j+{b_j}^2)\) |
|---|
| \(kx+b=y\) |
于是我们惊奇地发现, 状态转移方程竟然可以看作一条斜率为 \(2a_i\) , 截距为 \(dp_i-{a_i}^2\) 的直线和一个在 \((b_j,dp_j+{b_j}^2)\) 的点(我管它叫决策点)!
所以, "转移" 这个过程就可以理解为找到一个斜率为 \(2a_i\) 的直线交于一个已有的决策点.

其中, 红色直线表示 \(dp_i\) 对应的直线,绿色直线表示一个可能的 \(dp_j\) 对应的直线, 点 A 表示这个 \(dp_j\) 对应的决策点, 点 B 表示 \(dp_i\) 对应的决策点.
所以我们怎么找一条最优的直线, 使得 \(dp_i\) 最小? 难道要枚举 \(j\) 吗?
当然不用. 因为 \(dp_i-{a_i}^2\) 只与 \(i\) 有关, 所以只要这条直线的截距最小, \(dp_i\) 就是最小的. 我们假设平面上已经有一堆可供转移的决策点和直线:

可以想象 \(dp_i\) 对应的直线从下往上移动 (别忘了这条直线的斜率不变) , 显然它第一个接触到的点就是最优决策点.

如果您学过计算几何 (我没学过QAQ) , 您可以马上发现潜在的最优决策点都在这一堆点的下凸包上!

所以我们只需要用一个单调队列来维护这个凸包就可以了.
具体怎么维护等到以后再写罢, 博主累了.
综上所述, 我们通过发掘状态转移方程的性质做到了摊还 \(\Theta(1)\) 的转移, 非常优秀.
代码:
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
#define int ll
const int MAXN=50000;
int n,L,c[MAXN+5],sum[MAXN+5],dp[MAXN+5];
deque<int> q;
int a(int i){return sum[i]+i;}
int b(int i){return sum[i]+i+L+1;}
int X(int i){return b(i);}
int Y(int i){return (dp[i])+(b(i)*b(i));}
double slope(int i,int j){return double(Y(i)-Y(j))/double(X(i)-X(j));}
signed main(){
ios::sync_with_stdio(false);
cin>>n>>L;
for(int i=1;i<=n;i++){
cin>>c[i];sum[i]=sum[i-1]+c[i];
}
q.push_back(0);
for(int i=1;i<=n;i++){
double qwq=114514.1919810;
if(q.size()>=2)qwq=slope(q[0],q[1]);
while(q.size()>=2&&slope(q[0],q[1])<double(2*a(i))){
q.pop_front();
}
int j=q.front();
dp[i]=dp[j]+(a(i)-b(j))*(a(i)-b(j));
while(q.size()>=2&&slope(q[q.size()-1],q[q.size()-2])>slope(q[q.size()-2],i))q.pop_back();
q.push_back(i);
}
cout<<dp[n]<<endl;
return 0;
}
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总
深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal
有没有办法在Ruby中动态创建数组?例如,假设我想遍历用户输入的书籍数组:books=gets.chomp用户输入:"TheGreatGatsby,CrimeandPunishment,Dracula,Fahrenheit451,PrideandPrejudice,SenseandSensibility,Slaughterhouse-Five,TheAdventuresofHuckleberryFinn"我把它变成一个数组:books_array=books.split(",")现在,对于用户输入的每一本书,我想用Ruby创建一个数组。伪代码来做到这一点:x=0books_array.
我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or
我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO
首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟
如何学习ruby的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/
我正在尝试动态构建一个多维数组。我想要的基本上是这样的(为简单起见写出来):b=0test=[[]]test[b]这给了我错误:NoMethodError:undefinedmethod`test=[[],[],[]]而且它工作正常,但在我的实际使用中,我不会事先知道需要多少个数组。有一个更好的方法吗?谢谢 最佳答案 不需要像您正在使用的索引变量。只需将每个数组附加到您的test数组:irb>test=[]=>[]irb>test[["a","b","c"]]irb>test[["a","b","c"],["d","e","f"]]
如何只加载map边界内的标记gmaps4rails?当然,在平移和/或缩放后加载新的。与此直接相关的是,如何获取map的当前边界和缩放级别? 最佳答案 我是这样做的,我只在用户完成平移或缩放后替换标记,如果您需要不同的行为,请使用不同的事件监听器:在你看来(index.html.erb):{"zoom"=>15,"auto_adjust"=>false,"detect_location"=>true,"center_on_user"=>true}},false,true)%>在View的底部添加:functiongmaps4rail