洛谷 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的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序 ...
随机推荐
- .Net项目中NLog的配置与使用
引言: 因为之前在项目开发中一直都是使用的Log4Net作为项目的日志记录框架,最近忽然感觉对它已经有点腻了,所以尝试着使用了NLog作为新项目的日志记录框架(当然作为一名有志向的攻城狮永远都不能只局 ...
- 基于SpringCloud的Microservices架构实战案例-架构拆解
自第一篇< 基于SpringCloud的Microservices架构实战案例-序篇>发表出来后,差不多有半年时间了,一直也没有接着拆分完,有如读本书一样,也是需要契机的,还是要把未完成的 ...
- BeanUtils.copyProperties的用法
实现原理 原理 target.set + source的属性名(source.get + source的属性名):所有source必须有get方法,target必须有set方法 一. springfr ...
- linux应用程序设计--GCC程序编译
GCC程序编译 linux系统下的GCC(GNU C Compiler)是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作之一.GCC可以在多种硬件平台上编译出可执行程序,其执行效率与一 ...
- springcloud-高可用部署
1.场景描述 前端时间只简单介绍了下springcloud的高可用方案(springcloud高可用方案),今天详细介绍下如何实施springcloud的高可用部署. 2.解决方案 2.1 架构方案 ...
- [virtualenvwrapper] 命令小结
创建环境 mkvirtualenv env1 mkvirtualenv env2 环境创建之后,会自动进入该目录,并激活该环境. 切换环境 workon env1 workon env2 列出已有环境 ...
- 基于Bitnami gitlab OVA包的gitlab 环境搭建
前言 最近在折腾gitlab,本篇记录搭建的过程方便以后查找 环境 Windows server + VMware 安装 为方便本次我们直接采用Bitnami的VOA安装包(VOA格式可同时兼容Vir ...
- Linux命令大全(简)
rm--删除文件和目录 -i 删除一个已存在的文件前,提示用户进行确认. -r 递归的删除目录. mkdir--创建目录 cp--复制文件和目录 -i 在覆盖一个已存在的目录前,提示用户进 ...
- c#六大设计原则(以仪器代码为例)
[有格式的原文请到https://www.cnc6.cn/c六大设计原则/文末下载] 软件设计原则常见的有6大原则,分别为: ①单一职责原则: ②开闭原则: ③依赖倒置原则: ④里氏替换原则: ⑤接口 ...
- CSDN 免积分下载
你可能不相信这个标题,那么打开下面的链接试试吧 ↓↓↓ Github项目 最新功能 ↓↓↓ 0积分资源搜索 0积分资源搜索(备用地址) CSDN资源导出 CSDN资源下载体验群 (每日可免费下载一次) ...