【刷题笔记】DP优化-斜率优化
斜率优化,是一种利用斜率的优化(废话)
关于数论:咕咕咕
部分内容参考自学长
如果有这样的一个状态转移方程:
\]
如果\(val(j,i)=A(i)+B(j)\)可以用单调队列解决
当\(val(j,i)=(A(i)+B(j))^2\)时,就可以考虑斜率优化。
关键词:斜率,凸包,单调队列
特别行动队
看到这题,暴力\(DP\)应该比较好想:
\]
看见平方,把他展开:
\]
\]
一定的项就可以提出去
\]
所以,我们考虑\(val_j=f[j]+A\cdot sum[j]^2-2A\cdot sum[i]\cdot sum[j]-B\cdot sum[j]\)这一部分的取值
设当前想要转移到的状态为\(i\),\(j,k\)是之前的两个转移点
那么当\(j<k\),且\(val_j\leq val_k\)时,\(j\)劣于\(k\)。
写出来就是
\]
\]
\]
\]
(注意最后有个变号)
令\(g[t]=f[t]+A\cdot sum[t]^2-B\cdot sum[t]\),原式就会变成:
\]
好——舒——服——啊——这就直接上斜率优化了
Latex打得我要死了
看题,发现\(A<0\),而\(sum\)是递增的,所以如果一个\(sum[i]\)满足条件,之后的所有\(sum[i]\)也都满足条件,也就是说对于之后的所有转移,都有\(j\)劣于\(k\)。
冷静分析,发现是个上凸包,因为根据推出来的式子弹队头,斜率大于等于当前的都会被弹掉
然后同样的道理来弹队尾!
(最后一步的分析第一次做斜率优化想了半个小时……不过想过去是真的豁然开朗)
磕磕绊绊弄出来的混乱程序
#include<bits/stdc++.h>
#define ll long long
#define db double
#define ZZ_zuozhe int main()
#define Arknights return 0
using namespace std;
#define MAXN 1000005
ll q[MAXN];
db f[MAXN],k[MAXN],sum[MAXN],y[MAXN];
ZZ_zuozhe
{
ll n;
scanf("%lld",&n);
db a,b,c,nowk;
scanf("%lf%lf%lf",&a,&b,&c);
for(int i=1;i<=n;i++)
{
scanf("%lf",&sum[i]);
sum[i]+=sum[i-1];
}
ll h=1,t=1,j;
for(int i=1;i<=n;i++)
{
nowk=2*a*sum[i];
while(h<t&&k[h]>=nowk)h++;
f[i]=y[q[h]]-nowk*sum[q[h]]+(a*sum[i]+b)*sum[i]+c;
y[i]=f[i]+(a*sum[i]-b)*sum[i];
while(h<t&&k[t-1]<=(y[q[t]]-y[i])/(sum[q[t]]-sum[i]))--t;
k[t]=(y[q[t]]-y[i])/(sum[q[t]]-sum[i]);
q[++t]=i;
}
printf("%.0lf\n",f[n]);
Arknights;
}
我的娘啊太短了吧……其实还可以再压行
有一点需要注意的是因为单调队列里存了线段斜率,这是代表两个点的,所以这里只能用\(f<t\)配\(f=t=1\),我原来写的单调队列这里会挂……
玩具装箱
先打暴力:
\]
按照我们的一贯作风,这个时候应该化简了
这一大坨平方摆在这里化个麦乐鸡腿堡啊!
不急不急,咱们换个元,把含\(i,j\)的项合在一起,令\(g[t]=sum[t]+t\),这里就有
\]
然后因为\(g[i]\)是可求的,直接把他提出来就好
\]
\]
接下来,考虑\(f[j]+(g[j]+1+L)^2-2\cdot g[i]\cdot (g[j]+1+L)\)这一部分
设当前要转移到\(i\),之前有两个状态\(j,k\)
则当\(j<k\),且\(val_j \geq val_k\)时,\(j\)劣于\(k\)。
列出式子:
\]
然后就是欢乐化简环节,这里就直接给结果了\(qwq\)
\]
(注意变号)
令\(h[t]=f[t]+(g[t]+L+1)^2\),则有
\]
一般形式出来了,代码就好写了~
右面单调递增,和上一题恰恰相反,单调队列下凸包,代码仍然极短>.<
#include<bits/stdc++.h>
#define ll long long
#define db double
#define ZZ_zuozhe int main()
#define Arknights return 0
using namespace std;
#define MAXN 50005
ll q[MAXN];
db f[MAXN],g[MAXN],h[MAXN],sum[MAXN],L,k[MAXN];
db nowk;
ll n;
inline db slope(ll j,ll k){return (h[j]-h[k])/(g[j]-g[k]);}
ZZ_zuozhe
{
scanf("%lld%lf",&n,&L);
h[0]=(L+1)*(L+1);
for(int i=1;i<=n;i++)
{
scanf("%lf",&sum[i]);
sum[i]+=sum[i-1];
g[i]=sum[i]+i;
}
ll he=1,t=1;
for(int i=1;i<=n;i++)
{
nowk=2*g[i];
while(he<t&&k[he]<=nowk)he++;
f[i]=f[q[he]]+(g[i]-g[q[he]]-1-L)*(g[i]-g[q[he]]-1-L);
h[i]=f[i]+(g[i]+L+1)*(g[i]+L+1);
while(he<t&&k[t-1]>=slope(q[t],i))t--;
k[t]=slope(q[t],i);
q[++t]=i;
}
printf("%.0lf",f[n]);
Arknights;
}
仓库建设
上暴力!
\]
还要求和好麻烦啊……那就化简一下
\]
这个求和就可以前缀和优化了呢……
设\(sP[t]=\sum\limits_{i=1}^{t}P[i]\),\(sPX[t]=\sum\limits_{i=1}^{t}P[i]\cdot X[i]\),就可以得到:
\]
怎么越来越乱了,走了走了打暴力去
且慢!你似乎忘了把只含\(i\)的式子提出来……
于是:
\]
咱就只用考虑\(f[j]-X[i]\cdot sP[j]+sPX[j]\)这一块
设当前要转移到\(i\),之前有两个状态\(j,k\)(套路出来了
则当\(j<k\),且\(val_j \geq val_k\)时,\(j\)劣于\(k\)。
代入就是
\]
\]
\]
令\(g[t]=f[t]+sPX[t]\),强行搞出一般形式:
\]
舒服了,上兵器,和上一题类似,单调队列下凸包。
这题数据很大时\(double\)似乎精度堪忧……换了\(long long\)就没事了,不过记得把所有不等号的等于都去掉……
#include<bits/stdc++.h>
#define ll long long
#define db double
#define ZZ_zuozhe int main()
#define Arknights return 0
using namespace std;
#define MAXN 1000005
ll n;
ll q[MAXN];
ll p[MAXN],x[MAXN],c[MAXN],sp[MAXN],spx[MAXN],f[MAXN],nowk,k[MAXN],g[MAXN];
inline db slope(ll j,ll k){return 1.0*(g[j]-g[k])/(sp[j]-sp[k]);}
ZZ_zuozhe
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&x[i],&p[i],&c[i]);
sp[i]=sp[i-1]+p[i];
spx[i]=spx[i-1]+p[i]*x[i];
}
ll h=1,t=1;
for(int i=1;i<=n;i++)
{
nowk=x[i];
while(h<t&&k[h]<nowk)h++;
f[i]=f[q[h]]-x[i]*sp[q[h]]+spx[q[h]]+c[i]+x[i]*sp[i]-spx[i];
g[i]=f[i]+spx[i];
while(h<t&&k[t-1]>slope(q[t],i))t--;
k[t]=slope(q[t],i);
q[++t]=i;
}
printf("%lld",f[n]);
Arknights;
}
土地购买
发现每次买地是按最大长和最大宽的乘积计费的,所以如果某块土地的长和宽都小于另外某块土地的,这块土地实际上就不会对答案产生贡献了
然后就可以写dp:(记得考虑已知性质
\]
通过排序使\(l\)单调递增,\(w\)单调递减,就可以上斜率优化了
设当前要转移到\(i\),之前有两个状态\(j,k\)(我又开始复读了
则当\(j<k\),且\(val_j \geq val_k\)时,\(j\)劣于\(k\)。
代入:
\]
\]
莫名很好化……
右面单调递增,单调队列维护个下凸包即可
讲个笑话,我输出\(f[n]\),\(Wa\) \(10\)调了半上午:)
#include<bits/stdc++.h>
#define ll long long
#define db double
#define ZZ_zuozhe int main()
#define Arknights return 0
#define MAXN 50005
using namespace std;
struct land
{
ll w,l;
}a[MAXN],b[MAXN];
ll cnt=0;
inline bool cmp(land a,land b){return (a.l!=b.l?a.l<b.l:a.w<b.w);}
ll n,q[MAXN];
db f[MAXN],k[MAXN];
inline db slope(ll j,ll k){return 1.0*(f[j]-f[k])/(b[k+1].w-b[j+1].w);}
ZZ_zuozhe
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].w,&a[i].l);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
while(cnt&&(a[i].w>=b[cnt].w||a[i].l==b[cnt].l))cnt--;
b[++cnt].w=a[i].w;
b[cnt].l=a[i].l;
}
//for(int i=1;i<=cnt;i++)cout<<b[i].l<<' '<<b[i].w<<endl;
ll h=1,t=1;
db nowk;
for(int i=1;i<=cnt;i++)
{
nowk=b[i].l;
//cout<<"i:"<<i<<' '<<k[h]<<' '<<nowk<<endl;
while(h<t&&k[h]<nowk)h++;
f[i]=f[q[h]]+b[q[h]+1].w*b[i].l;
while(h<t&&k[t-1]>slope(q[t],i))t--;
k[t]=slope(q[t],i);
q[++t]=i;
//cout<<"head:"<<h<<' '<<"f["<<i<<"]="<<f[i]<<endl;
}
printf("%.0lf",f[cnt]);
Arknights;
}
【刷题笔记】DP优化-斜率优化的更多相关文章
- LeetCode刷题笔记-DP算法-取数问题
题目描述 (除数博弈论)爱丽丝和鲍勃一起玩游戏,他们轮流行动.爱丽丝先手开局. 最初,黑板上有一个数字 N .在每个玩家的回合,玩家需要执行以下操作: 选出任一 x,满足 0 < x < ...
- 【学习笔记】动态规划—斜率优化DP(超详细)
[学习笔记]动态规划-斜率优化DP(超详细) [前言] 第一次写这么长的文章. 写完后感觉对斜优的理解又加深了一些. 斜优通常与决策单调性同时出现.可以说决策单调性是斜率优化的前提. 斜率优化 \(D ...
- dp的斜率优化
对于刷题量我觉得肯定是刷的越多越好(当然这是对时间有很多的人来说. 但是在我看来我的确适合刷题较多的那一类人,应为我对知识的应用能力并不强.这两天学习的内容是dp的斜率优化.当然我是不太会的. 这个博 ...
- 《Data Structures and Algorithm Analysis in C》学习与刷题笔记
<Data Structures and Algorithm Analysis in C>学习与刷题笔记 为什么要学习DSAAC? 某个月黑风高的夜晚,下班的我走在黯淡无光.冷清无人的冲之 ...
- PTA刷题笔记
PTA刷题记录 仓库地址: https://github.com/Haorical/Code/tree/master/PTA/GPLT 两周之内刷完GPLT L2和L3的题,持续更新,包括AK代码,坑 ...
- Python 刷题笔记
Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...
- 【笔记篇】斜率优化dp(四) ZJOI2007仓库建设
传送门戳这里>>> \(n\leq1e6\), 显然还是\(O(n)\)的做法. 这个题有个条件是只能运往编号更大的工厂的仓库, 这也是写出朴素dp的方程的条件. 我们令\(f[i] ...
- 【笔记篇】斜率优化dp(一) HNOI2008玩具装箱
斜率优化dp 本来想直接肝这玩意的结果还是被忽悠着做了两道数论 现在整天浑浑噩噩无心学习甚至都不是太想颓废是不是药丸的表现 各位要知道我就是故意要打删除线并不是因为排版错乱 反正就是一个del标签嘛并 ...
- 【笔记篇】斜率优化dp(二) SDOI2016征途
=======传=送=门======= 搜题目名会搜出很多奇怪的东西... 这个题目似乎有点毒? 比如在bzoj和loj上可以1A的代码上会在luogu TLE 2个点, 在cogs TLE 10个点 ...
随机推荐
- [Luogu P1345] [USACO5.4]奶牛的电信Telecowmunication (最小割)
题面 传送门:https://www.luogu.org/problemnew/show/P1345 ] Solution 这道题,需要一个小技巧了解决. 我相信很多像我这样接蒟蒻,看到这道题,不禁兴 ...
- 浅谈 Tarjan 算法
目录 简述 作用 Tarjan 算法 原理 出场人物 图示 代码实现 例题 例题一 例题二 例题三 例题四 例题五 总结 简述 对于初学 Tarjan 的你来说,肯定和我一开始学 Tarjan 一样无 ...
- JVM学习(五) -执行子系统
虚拟机和物理机的区别.两种都有代码执行能力.物理机的执行引擎是建立在处理器.硬件.指令集和操作系统上.而虚拟机的执行引擎是有自己实现的.因此可以自行的制定指令集和执行引擎的结构关系. 个人理解:分为三 ...
- tomcat 404报错 问题可能之一
一个tomcat下多个应用:我的应用xxx启动不起来,页面报错404: May 29, 2015 5:58:37 PM org.apache.catalina.core.StandardContext ...
- Shell脚本常用命令整理
该笔记主要整理了一些常见的脚本操作命令,大致如下(持续补充中): 1. while.for循环 1. while.for循环 #!/bin/bash # while循环 v_start_date=${ ...
- [MIT6.006] 9. Table Doubling, Karp-Rabin 双散列表, Karp-Rabin
在整理课程笔记前,先普及下课上没细讲的东西,就是下图,如果有个操作g(x),它最糟糕的时间复杂度为Ο(c2 * n),它最好时间复杂度是Ω(c1 * n),那么θ则为Θ(n).简单来说:如果O和Ω可以 ...
- Ceph根据Crush位置读取数据
前言 在ceph研发群里面看到一个cepher在问关于怎么读取ceph的副本的问题,这个功能应该在2012年的时候,我们公司的研发就修改了代码去实现这个功能,只是当时的硬件条件所限,以及本身的稳定性问 ...
- JavaScript高级程序设计(第四版) -- 随笔 -- 数组(未完)
数组方法 .every() 与 .some() 传给两个个方法的函数都接收3个参数:数组元素.元素索引和数组本身. .every() -- 对于每一项都需要返回true,它才会返回true 若中途有一 ...
- Tomcat口令暴力猜解&&后台getshell
Tomcat环境搭建 windows系统xampp搭建tomcat linux yum搭建tomcat 修改tomcat目录下的conf/tomcat-users.xml文件开启管理后台口令认证 &l ...
- docker漏洞复现环境搭建
0x00 docker简介 把原来的笔记整理了一下,结合前几天的一个漏洞,整理一篇简单的操作文档,希望能帮助有缘人. docker是一个开源的应用容器引擎,开发者可以打包自己的应用到容器里面,然后迁移 ...