斜率优化
来源:互联网 发布:在数据库中存储的是 编辑:程序博客网 时间:2024/04/26 10:50
题目描述
你有一支由n名预备役士兵组成的部队,士兵从1到n编号,
要将他们拆分成若干特别行动队调入战场。
出于默契的考虑,同一支特别行动队中队员的编号应该连续,
即为形如(i, i + 1, …, i + k)的序列。
编号为i的士兵的初始战斗力为xi ,一支特别行动队的初始战斗力x为队内士兵初始战斗力之和,
即x = xi + xi+1 + … + xi+k。
通过长期的观察,你总结出一支特别行动队的初始战斗力x将按如下经验公式修正为
x':x' = ax^2 + bx + c,其中a, b, c是已知的系数(a < 0)。
作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队修正后战斗力之和最大。
试求出这个最大和。例如,你有4名士兵,x1 = 2, x2 = 2, x3 = 3, x4 = 4。
经验公式中的参数为a = –1, b =10, c = –20。
此时,最佳方案是将士兵组成3个特别行动队:
第一队包含士兵1和士兵2,第二队包含士兵3,第三队包含士兵4。
特别行动队的初始战斗力分别为4, 3, 4,修正后的战斗力分别为4, 1, 4。
修正后的战斗力和为9,没有其它方案能使修正后的战斗力和更大。
输入格式
输入由三行组成。第一行包含一个整数n,表示士兵的总数。
第二行包含三个整数a, b, c,经验公式中各项的系数。
第三行包含n个用空格分隔的整数x1, x2, …, xn,
分别表示编号为1, 2, …, n的士兵的初始战斗力。
【数据范围】
20%的数据中,n ≤ 1000;50%的数据中,n ≤ 10,000;
100%的数据中,1 ≤ n ≤ 1,000,000,–5 ≤ a ≤ –1,|b| ≤ 10,000,000,
|c| ≤ 10,000,000,1 ≤ xi ≤ 100。
输出格式
输出一个整数,表示所有特别行动队修正后战斗力之和的最大值。
样例输入
4
-1 10 -20
2 2 3 4
样例输出
9
这是一个斜率优化的题
朴素的可以想到有
dp[i] = dp[j] + a*SQR(s[i]-s[j])+b*(s[i]-s[j])+c
对于dp[i]有两个决策j,k,且k更优,则有
dp[k]-dp[j]-2*s[i]*s[k]+2*s[i]*s[j]+a*s[k]^2-a*s[j]^2-b*s[k]+b*s[j]>0
整理得
(dp[k]+a*s[k]^2-b*s[k]) – (dp[j]+a*s[j]^2-b*s[j]) > 2*a*s[i]*(s[k]-s[j])
设函数F(i) = dp[i]+a*s[i]^2-b*s[i]
X(i,j)=(F(k) – F(j)) / (s[k] – s[j])
这就是斜率式了,后面就是维护一个单调队列就好了
第一次写(抄)斜率优化,看了半天定义,以前寥寥草草知道一点队尾的操作,不知道队头还有操作
下面抄一段证明。。。。
现在从左到右,还是设k<j<i,如果g[i,j]<g[j,k],那么j点便永远不可能成为最优解,可以直接将它踢出我们的最优解集。为什么呢?
我们假设g[i,j]<sum[i],那么就是说i点要比j点优,排除j点。
如果g[i,j]>=sum[i],那么j点此时是比i点要更优,但是同时g[j,k]>g[i,j]>sum[i]。这说明还有k点会比j点更优,同样排除j点。
排除多余的点,这便是一种优化!
接下来看看如何找最优解。
设k<j<i。
由于我们排除了g[i,j]<g[j,k]的情况,所以整个有效点集呈现一种上凸性质,即k j的斜率要大于j i的斜率。
这样,从左到右,斜率之间就是单调递减的了。当我们的最优解取得在j点的时候,那么k点不可能再取得比j点更优的解了,于是k点也可以排除。换句话说,j点之前的点全部不可能再比j点更优了,可以全部从解集中排除。
于是对于这题我们对于斜率优化做法可以总结如下:
1,用一个单调队列来维护解集。
2,假设队列中从头到尾已经有元素a b c。那么当d要入队的时候,我们维护队列的上凸性质,即如果g[d,c]<g[c,b],那么就将c点删除。直到找到g[d,x]>=g[x,y]为止,并将d点加入在该位置中。
3,求解时候,从队头开始,如果已有元素a b c,当i点要求解时,如果g[b,a]<sum[i],那么说明b点比a点更优,a点可以排除,于是a出队。最后dp[i]=getDp(q[head])。
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;#define SQR(x) (x) * (x)typedef long long LL;LL n, a, b, c, s[1000010], q[1000010], data[1000010];inline double F(int k){return data[k] + a * SQR(s[k]) - b * s[k];}inline double X(int k, int j){return (F(k) - F(j)) / (s[k] - s[j]);}int main(){ int i; cin>>n>>a>>b>>c; s[0] = 0; for(i = 1; i <= n; i++){cin>>s[i]; s[i] += s[i - 1];} int head = 0, tail = 0; q[0] = data[0] = 0;//习惯于这么弄初始状态。 for(i = 1; i <= n; i++) { int p = 2 * a * s[i]; while(head < tail && X(q[head], q[head + 1]) > p) ++head; int xx = q[head]; data[i] = data[xx] + a * SQR(s[i] - s[xx]) + b * (s[i] - s[xx]) + c; while(head < tail && X(q[tail], i) > X(q[tail - 1], q[tail])) --tail; q[++tail] = i; } cout<<data[n];return 0;}
- 斜率优化
- 斜率优化
- 斜率优化
- 斜率优化
- 斜率优化
- 斜率优化
- 斜率优化
- 斜率优化
- 斜率优化
- 斜率优化
- DP(斜率优化)
- 【斜率优化DP】Batch_Scheduling
- Hdu-2993斜率优化
- HDOJ-3480斜率优化
- HDOJ2829-斜率优化
- 斜率优化 [学习笔记]
- dp优化--斜率
- 斜率优化DP
- 如何从AD中彻底删除Skype For Business(下篇)
- android内容提供者ContentProvider,UriMatcher和内容观察者ContentObserver常见使用
- 九度OJ 1020 最小长方形
- QtQuick动态创建组件
- 线程(一)线程安全和不安全
- 斜率优化
- 【c++程序】字符串反转
- 2016~六月英语·活动·成长
- Android 自定义线程池
- 练习四1005
- XListView的使用
- Rxjava四步走到高级掌握
- Java(object类及方法简介)
- Activiti(二)流程实例