洛谷 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的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序 ...
随机推荐
- Java 技术交流群,微信群
专注Java相关技术:SSM.Spring全家桶.微服务.MySQL.集群.dubbo.分布式.中间件.Linux.网络.多线程.Jenkins.Nexus.Docker.ELK等等! 由于微信群限制 ...
- java Springboot 生成 二维码 +logo
上码,如有问题或者优化,劳请广友下方留言 1.工具类 import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHint ...
- WordPress教程之页面、菜单、媒体库、高级定制
本系列教程链接: 怎么快速搭建一个WordPress网站 Wordpress教程之初识WordPress Wordpress教程之如何入门WordPress Wordpress教程之如何创建博客内容 ...
- Prim算法与Kruskal(没有代码)
两个最小生成树算法, 都有一个共同的思想: 这棵树是一点一点长大的; 并且每次生长, 都是贪心的. 不同之处是: Kruscal算法是以边为中心的, 每次找最小的并且有用的边添加到树上; Prim算法 ...
- golang开发:类库篇(四)配置文件解析器goconfig的使用
为什么要使用goconfig解析配置文件 目前各语言框架对配置文件书写基本都差不多,基本都是首先配置一些基础变量,基本变量里面有环境的配置,然后通过环境变量去获取该环境下的变量.例如,生产环境跟测试环 ...
- 【CYH-02】NOIp考砸后虐题赛:转换式:题解
这道题真的不难吧. 如@AKEE@AKEE@AKEE 大佬所说,此题的确可以将n推广到一般情况. 但题面还是良心的只到了N<=4N<=4N<=4 以目前的题目来看,简单模拟即可. 分 ...
- Java编程基础阶段笔记 day01 Java语言概述
目录内容 DOS命令 电脑配置 Java语言的特性 Java两种核心机制 Java语言环境搭建 第一个Java程序 注释 Java语句说明 编程风格 作业 常用的DOS命令 dir : 列出当 ...
- EF Core懒人小技巧之拒绝DbSet
前言 最近在项目中使用EF Core的频率越来越高,当项目比较大的时候,疯狂往DbContext中加各种DbSet,你会不会特难受?如果你是一键生成的大佬,那么请忽略本文.本文旨在不写 DbSet,那 ...
- CSDN 免积分下载
你可能不相信这个标题,那么打开下面的链接试试吧 ↓↓↓ Github项目 最新功能 ↓↓↓ 0积分资源搜索 0积分资源搜索(备用地址) CSDN资源导出 CSDN资源下载体验群 (每日可免费下载一次) ...
- python-crud
Python Fast CRUD https://github.com/aleimu/python-crud 目的 本项目采用了一系列Python中比较流行的组件,可以以本项目为基础快速搭建Restf ...