洛谷 P3628 特别行动队
洛谷题目页面传送门
题意见洛谷。
这题一看就是DP。。。
设\(dp_i\)表示前\(i\)个士兵的最大战斗力。显然,最终答案为\(dp_n\),DP边界为\(dp_0=0\),状态转移方程为\(dp_i=\max\limits_{j\in[0,i)}\left\{dp_j+a\left(\sum\limits_{k=j+1}^ix_k\right)^2+b\sum\limits_{k=j+1}^ix_k+c\right\}\)。
这其中要求区间和,可以先预处理出前缀和数组\(Sum\)。那么方程变为了\(dp_i=\max\limits_{j\in[0,i)}\left\{dp_j+a(Sum_i-Sum_j)^2+b(Sum_i-Sum_j)+c\right\}\)。
朴素地转移是\(\operatorname{O}\left(n^2\right)\)的,肯定会超时,于是要考虑优化。乍一看,这方程中\(\max\)的下界不动、上界在DP过程中随状态变量\(i\)单调递增,里面又有既和状态变量\(i\)又和决策变量\(j\)相关的项\((Sum_i-Sum_j)^2\)……这不就是斜率优化的标志吗?
我们假设有两个决策变量\(j,k\)满足\(j>k\)且\(j\)比\(k\)优,那么
\]
即
\]
去括号,得
\]
即
\]
把只关于决策变量的项放到左边来,既关于状态变量又关于决策变量的项放到右边去,得
\]
由于\(j>k,x_i>0\),所以\(Sum_j-Sum_k>0\)(这就是要设\({j>k}\)的原因),那么可以把\(Sum_j-Sum_k\)除到左边去且不等号方向不变(同理,设\(j<k\)也可以,只不过不等号要变方向),得
\]
这时,左边的东西似乎很眼熟……是什么呢……斜率!这不就相当于以\({dp_i+aSum_i^2-bSum_i}\)为点\({i}\)的纵坐标,以\({Sum_i}\)为点\({i}\)的横坐标的直角坐标系中,点\({k}\)与点\({j}\)之间直线的斜率吗?
我们令\(f(j,k)\)为这个斜率。现在设\(j,k,o\)是三个决策变量,满足\(j>k>o\),那么若\(f(j,k)\ge f(k,o)\),可以证明\(k\)永远不可能成为最优决策。因为当\(f(j,k)>2aSum_i\)时,\(j\)比\(k\)优,\(k\)不是最优的;当\(f(j,k)\le 2aSum_i\)时,结合\(f(j,k)\ge f(k,o)\)可以得出\(f(k,o)\le 2aSum_i\),即\(k\)不比\(o\)优,此时\(k\)也不是最优的。
所以我们要维护一个两个元素之间的直线的斜率严格单调递减的决策序列\(J\)(下标从\(1\)开始),即一个上凸壳,只有\(J\)里的决策才有可能最优。
但是\(J\)里有那么多决策,那个才是最优的呢?如果\(J\)中没有一个斜率\(\le2aSum_i\),即所有斜率都\(>2aSum_i\),显然\(J_{|J|}\)是最优决策;如果有,设\(J_j\)是第一个\(\le2aSum_i\)的斜率所对应的直线的左端点,那么\(J_j\)是最优决策。
不难想到,我们可以维护一个单调栈充当\(J\),装着对于目前的\(i\),所有可能最优的决策,然后二分找到最优决策。可是在DP的过程中,\(2aSum_i\)也是单调递减的(因为\(a<0\)),也就是说今朝一个斜率\(>2aSum_i\),那么它以后都要\(>2aSum_i\),即它对应的直线的左端点以后都不会成为最优决策,那就把这个废点弹出吧!用一个单调队列,在每次找最优决策时,不断地弹出队首(自带音效biubiubiu)直到第\(1\)个斜率\(\le2aSum_i\)为止。这样最优决策就是队首了。
\([1,n]\)内每个元素最多入队出队各一次,所以单调队列操作的总时间复杂度是\(\operatorname{O}(n)\),DP也是\(\operatorname{O}(n)\)的,整个就是\(\operatorname{O}(n)\)啦!
最后再唠叨\(2\)句:
- 这题用
int
会爆炸,要用long long
。 - 单调队列用STL里的
deque
比较慢,最好自己写。
讲了这么多,终于上代码了(逃
#include<bits/stdc++.h>
using namespace std;
#define int long long//防爆int
#define N 1000000
inline int sq(int x){return x*x;}//平方
int Sum[N+1]/*前缀和*/,q[N]/*单调队列*/,dp[N+1]/*dp[i]表示前i个士兵的最大战斗力*/,a,b,c;
inline double son(int j,int k)/*纵坐标之差,即斜率的分子*/{return (dp[j]+a*sq(Sum[j])-b*Sum[j])-(dp[k]+a*sq(Sum[k])-b*Sum[k]);}
inline double ma(int j,int k)/*横坐标之差,即斜率的分母*/{return Sum[j]-Sum[k];}
inline double f(int j,int k)/*斜率*/{return son(j,k)/ma(j,k);}
signed main(){
int n/*士兵个数*/,head=0,tail=0,i;scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
for(i=1;i<=n;i++){
int x;scanf("%lld",&x);
Sum[i]=Sum[i-1]+x;//预处理前缀和
}
q[tail++]=0;//初始有一个决策0
for(i=1;i<=n;i++){//状态转移
while(head+1<tail&&f(q[head+1],q[head])>2*a*Sum[i])head++;//弹出废点
dp[i]=dp[q[head]]+a*sq(Sum[i]-Sum[q[head]])+b*(Sum[i]-Sum[q[head]])+c;//最佳决策是队首,转移
//转移完了之后,i成了i+1的决策,压入队列
while(head+1<tail&&f(i,q[tail-1])>=f(q[tail-1],q[tail-2]))tail--;//维护队尾单调性
q[tail++]=i;//入队
// printf("dp[%d]=%d\n",i,dp[i]);
}
printf("%lld",dp[n]);//答案为dp[n]
return 0;
}
洛谷 P3628 特别行动队的更多相关文章
- [洛谷P3628] [APIO2010]特别行动队
洛谷题目链接:[APIO2010]特别行动队 题目描述 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 \(n\) 编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特别行动 ...
- 洛谷P3628 [APIO2010]特别行动队(动态规划,斜率优化,单调队列)
洛谷题目传送门 安利蒟蒻斜率优化总结 由于人是每次都是连续一段一段地选,所以考虑直接对\(x\)记前缀和,设现在的\(x_i=\)原来的\(\sum\limits_{j=1}^ix_i\). 设\(f ...
- 【洛谷 P3628】 [APIO2010]特别行动队 (斜率优化)
题目链接 斜率优化总结待补,请催更.不催更不补 \[f[i]=f[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c\] \[=f[j]+a*sum[i]^2+a*s ...
- 洛谷P3628 [APIO2010]特别行动队(斜率优化)
传送门 先写出转移方程$$dp[i]=max\{dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c\}$$ 假设$j$比$k$更优,则有$$dp[j]+a*(s ...
- 洛谷P3628 [APIO2010]特别行动队 斜率优化
裸题,注意队列下标不要写错 Code: #include<cstdio> #include<algorithm> #include<cmath> using nam ...
- 洛谷 P3628 [APIO2010]特别行动队
题意简述 将n个士兵分为若干组,每组连续,编号为i的士兵战斗力为xi 若i~j士兵为一组,该组初始战斗力为\( s = \sum\limits_{k = i}^{j}xk \),实际战斗力\(a * ...
- 【Luogu】P3628特别行动队(斜率优化DP)
题目链接 设c[i]是战斗力前缀和,f[i]是考虑前i个,且最后一组分到第i个士兵为止的战斗力之和 则有朴素状态转移方程 ;i<=n;++i) ;j<i;++j){ int x=c[i]- ...
- Bzoj2038/洛谷P1494 小Z的袜子(莫队)
题面 Bzoj 洛谷 题解 考虑莫队算法,首先对询问进行分块(分块大小为\(sqrt(n)\)),对于同一个块内的询问,按照左端点为第一关键字,右端点为第二关键字排序.我们统计这个区间内相同的颜色有多 ...
- 洛谷 P1219 八皇后【经典DFS,温习搜索】
P1219 八皇后 题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序 ...
随机推荐
- EF 使用遇到过的错误记录备忘
1. is only supported for sorted input in LINQ to Entities The method :只支持排序输入实体LINQ 的方法 是使用skip()时没 ...
- 使用wincc vbs脚本查找进程及如何运行进程
使用vbs代码查看某个进程是否在运行,本文要检查的进程名为 QRscan.exe,其代码如下: sub CheckProcess Dim WMI,Objs,Process,ObjSet WMI=Get ...
- 每周一个js重要概念之一 调用堆栈
js写了也有两年多了,大到复杂的后台系统,小到页面,还有日均300万的网页主站,HTML5的适配页面等等. 框架也杂七杂八接触了不少,从小的jquery.bootstrap.echarts等等,到大一 ...
- 20131214-EditPlus快捷键-第二十一天
EditPlus 快捷键 文件 FileFtpUpload Ctrl+Shift+S 上传文件到 FTP 服务器 FileNew Ctrl+N 新建普通的文本文档 FileNewHtml Ctrl ...
- Flink实战(六) - Table API & SQL编程
1 意义 1.1 分层的 APIs & 抽象层次 Flink提供三层API. 每个API在简洁性和表达性之间提供不同的权衡,并针对不同的用例. 而且Flink提供不同级别的抽象来开发流/批处理 ...
- 高德网络定位之“移动WiFi识别”
导读随着时代的发展,近10年来位置产业蓬勃发展,定位能力逐渐从低精度走向高精度,从部分场景走向泛在定位.设备和场景的丰富,使得定位技术和能力也不断的优化更新.定位能力包括GNSS.DR(航迹推算).M ...
- VUE v-for循环中每个item节点动态绑定不同函数方法
一. 业务场景: 一个title 处 可能有 一个或多个按钮, 按钮对应不同的响应事件 二. 思路 : 按钮个数 根据传入的数据length 来循环渲染, 每条数据对应的事件名称 通过动态绑定 三 ...
- PTA L2-031 深入虎穴 非dfs的一点想法
著名的王牌间谍 007 需要执行一次任务,获取敌方的机密情报.已知情报藏在一个地下迷宫里,迷宫只有一个入口,里面有很多条通路,每条路通向一扇门.每一扇门背后或者是一个房间,或者又有很多条路,同样是每条 ...
- 从国际象棋与象棋的走法差异,再趣说IT人提升能力和增收方式
之前我写过篇博文,用象棋的思维趣说IT人的职业发展和钱途,发现象棋中的一些思维能应用到我们程序员平时的职业发展中. 当从大学毕业的程序员干个五六年以后,也达到了高级开发的水平,工作环境应该能摆脱动荡, ...
- 安装win10体验
没事干了,心血来潮弄了个win10专业版. 讲硬盘重新分区了,没办法,原来分的太少了. 使用winpe启动,直接将下载的win10还原到c盘,成功启动,设置的时候让提示输入id,没有啊?研究发现可以先 ...