斜率优化第一题! HDU3507 | 单调队列优化DP

放一手原题



题解:

第一次写(抄)斜率优化,心里还是有点小激动的。讲一下怎么实现的!

首先我们可以考虑一个朴素的dp:DP[i]表示前i个数字的最少花费,显然我们有一个转移方程

DP[i]=min{DP[j]+M+(sum[i]-sum[j])^2}

但是N^2肯定会超时,我们考虑优化他

假设有k<j<i,如果令j对i的贡献比k好

显然我们有这样的式子

DP[j]+M+(sum[i]-sum[j])^2 < DP[k]+M+(sum[i]-sum[j])^2

把平方打开之后移项

可以得到

 ((DP[j]+sum[j]^2)- (DP[k]+sum[k]^2) )  / 2*(sum[j]-sum[k]) < sum[i]

可以把这个式子看成(yj - yk)/(xj - xk) 这样就得到了一个类似斜率的式子!

有了这些结论有什么用呢?

令G[i,j]表示刚刚的斜率式,依然有k<j<i

当j的决策比k优秀的时候,则满足G[i,j]>G[j,k]

我们可以用单调队列维护解集,利用斜率判断元素的入队和出队,这样可以使时间复杂度降低到O(n)了

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 500005
using namespace std;
int dp[N],q[N],sum[N],l,r,n,m;
int GetDp(int i,int j)
{
    return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]);
}
int GetUp(int j,int k)
{
    return dp[j]+sum[j]*sum[j]-(dp[k]+sum[k]*sum[k]);
}
int GetDown(int j,int k)
{
    return 2*(sum[j]-sum[k]);
}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        for (int i=1,x;i<=n;i++)
            scanf("%d",&x),sum[i]=sum[i-1]+x;
        l=r=0;
        q[r++]=0;
        for (int i=1;i<=n;i++)
        {
            while (l+1<r && GetUp(q[l+1],q[l])<=sum[i]*GetDown(q[l+1],q[l]))
                l++;
            dp[i]=GetDp(i,q[l]);
            while (l+1<r && GetUp(i,q[r-1])*GetDown(q[r-1],q[r-2])<=GetUp(q[r-1],q[r-2])*GetDown(i,q[r-1]))
                r--;
            q[r++]=i;
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/mrsheep/p/8387263.html

时间: 2024-08-29 23:14:04

斜率优化第一题! HDU3507 | 单调队列优化DP的相关文章

codevs3327选择数字(单调队列优化)

3327 选择数字 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入描述 Input Description 第一行两个整数n,k 以下n行,每行一个整数表示a[i]. 输出描述 Output Description 输出一个值表示答案. 样例输入 Sample Input 5 2

BZOJ 1855 [Scoi2010]股票交易 单调队列优化DP

题意:链接 方法:单调队列优化DP 解析:噢又是一道情况很多的题,然而三种更新我又落下一种导致样例不过,后来看题解才恍然- -最SB的一种更新居然忘了. 状态好想f[i][j]代表前i天有j双袜子时的最大利润. 三种更新: 第一种:f[i][j]=max(f[i][j],f[i?1][j]):(然而我忘了这一种) 第二种:买入f[i][j]=max(f[i][j],f[i?w?1][k]?(j?k)?a[i].ap)(k>=j?a[i].as); 第三种:卖出f[i][j]=max(f[i][j

【笔记篇】单调队列优化dp学习笔记&amp;&amp;luogu2569_bzoj1855股票交♂易

DP颂 DP之神 圣洁美丽 算法光芒照大地 我们怀着 崇高敬意 跪倒在DP神殿里 你的复杂 能让蒟蒻 试图入门却放弃 在你光辉 照耀下面 AC真心不容易 dp大概是最经久不衰 亘古不化的算法了吧. 而且有各种各样的类型 优化之类的. 一直dp都不怎么好. 而且也不太知道应该怎么提高. 基本见到不认识的dp方程就不大会推(但我会打表啊= = 所以dp还是很有的学的~ 正好最近刚刚肝了计算几何, 所以就顺带搞一下斜率优化dp一类的... 单调队列优化dp 单调队列大家都会吧? 不会的先出去学一下,

单调队列优化dp题目

附一链接,大多题型里面有,再附两题:https://blog.csdn.net/hjf1201/article/details/78729320 1.绿色通道 题目描述 Description <思远高考绿色通道>(Green Passage, GP)是唐山一中常用的练习册之一,其题量之大深受lsz等许多oiers的痛恨,其中又以数学绿色通道为最.2007年某月某日,soon-if (数学课代表),又一次宣布收这本作业,而lsz还一点也没有写-- 高二数学<绿色通道>总共有n道题目

[bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)

偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1943  Solved: 1004[Submit][Status][Discuss] Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo

[Vijos 1243]生产产品(单调队列优化Dp)

Description 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完

Tyvj1305最大子序和(单调队列优化dp)

描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7当m=2或m=3时,S=5+1=6 输入格式 第一行两个数n,m第二行有n个数,要求在n个数找到最大子序和 输出格式 一个数,数出他们的最大子序和 测试样例1 输入 6 4 1 -3 5 1 -2 3 输出 7 备注 数据范围:100%满足n,m<=300000 是不超过m,不是选m个!!!!! /* 单调队列优化dp 单调队列维护的是前

poj 3017 Cut the Sequence(单调队列优化 )

题目链接:http://poj.org/problem?id=3017 题意:给你一个长度为n的数列,要求把这个数列划分为任意块,每块的元素和小于m,使得所有块的最大值的和最小 分析:这题很快就能想到一个DP方程 f[ i ]=min{ f[ j ] +max{ a[ k ] }}( b[ i ]<j<i,j<k<=i)     b[ i ]到 i的和大于m 这个方程的复杂度是O(n^2),明显要超时的(怎么discuss都说数据弱呢= =) 然后是优化了,首先当然是要优化一个最大

bzoj1855: [Scoi2010]股票交易--单调队列优化DP

单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w-1][k]+k*Ap[i]的单调性即可 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2010; 6 int