ID
Origin
Title
  20 / 60 Problem A HDU 3507 Print Article
  13 / 19 Problem B HDU 2829 Lawrence
  1 / 5 Problem C HDU 4528 小明系列故事――捉迷藏
  5 / 6 Problem D HDU 1300 Pearls
  0 / 42 Problem E HDU 2993 MAX Average Problem
  1 / 20 Problem F UVALive 5097 Cross the Wall
  5 / 12 Problem G HDU 3045 Picnic Cows
  2 / 4 Problem H HDU 3516 Tree Construction
  3 / 4 Problem I POJ 1160 Post Office
  3 / 5 Problem J POJ 1180 Batch Scheduling
  3 / 3 Problem K POJ 2018 Best Cow Fences
  2 / 4 Problem L POJ 3709 K-Anonymous Sequence
    Problem M POJ 2841 Navigation Game
  2 / 2 Problem N POJ 1260 Pearls
  2 / 4 Problem O UVA 12594 Naming Babies
  3 / 4 Problem P HDU 3480 Division
  1 / 1 Problem Q UVALive 6771 Buffed Buffet
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

20 / 60 Problem A HDU 3507 Print Article

此题是很基础的斜率DP的入门题。
题意很清楚,就是输出序列a[n],每连续输出的费用是连续输出的数字和的平方加上常数M
让我们求这个费用的最小值。
设dp[i]表示输出前i个的最小费用,那么有如下的DP方程:
dp[i]= min{ dp[j]+(sum[i]-sum[j])^2 +M } 0<j<i
其中 sum[i]表示数字的前i项和。
相信都能理解上面的方程。
直接求解上面的方程的话复杂度是O(n^2)
对于500000的规模显然是超时的。下面讲解下如何用斜率优化DP使得复杂度降低一维。

我们首先假设在算 dp[i]时,k<j ,j点比k点优。
也就是
dp[j]+(sum[i]-sum[j])^2+M <= dp[k]+(sum[i]-sum[k])^2+M;
所谓j比k优就是DP方程里面的值更小
对上述方程进行整理很容易得到:
[(dp[j]+sum[j]*sum[j])-(dp[k]+sum[k]*sum[k])] / 2(sum[j]-sum[k]) <=sum[i].
注意整理中要考虑下正负,涉及到不等号的方向。
左边我们发现如果令:yj=dp[j]+sum[j]*sum[j] xj=2*sum[j]
那么就变成了斜率表达式:(yj-yk)/(xj-xk) <= sum[i];
而且不等式右边是递增的。
所以我们可以看出以下两点:我们令g[k,j]=(yj-yk)/(xj-xk)
第一:如果上面的不等式成立,那就说j比k优,而且随着i的增大上述不等式一定是成立的,也就是对i以后算DP值时,j都比k优。
那么k就是可以淘汰的。
第二:如果 k<j<i 而且 g[k,j]>g[j,i] 那么 j 是可以淘汰的。
假设 g[j,i]<sum[i]就是i比j优,那么j没有存在的价值
相反如果 g[j,i]>sum[i] 那么同样有 g[k,j]>sum[i] 那么 k比 j优 那么 j 是可以淘汰的

所以这样相当于在维护一个下凸的图形,斜率在逐渐增大。
通过一个队列来维护。

/*
HDU 3507 */ #include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const int MAXN=; int dp[MAXN];
int q[MAXN];//队列
int sum[MAXN]; int head,tail,n,m;
// dp[i]= min{ dp[j]+M+(sum[i]-sum[j])^2 };
int getDP(int i,int j)
{
return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]);
} int getUP(int j,int k) //yj-yk部分
{
return dp[j]+sum[j]*sum[j]-(dp[k]+sum[k]*sum[k]);
}
int getDOWN(int j,int k)
{
return *(sum[j]-sum[k]);
} int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(scanf("%d%d",&n,&m)==)
{
for(int i=;i<=n;i++)
scanf("%d",&sum[i]);
sum[]=dp[]=;
for(int i=;i<=n;i++)
sum[i]+=sum[i-];
head=tail=;
q[tail++]=;
for(int i=;i<=n;i++)
{
//把斜率转成相乘,注意顺序,否则不等号方向会改变的
while(head+<tail && getUP(q[head+],q[head])<=sum[i]*getDOWN(q[head+],q[head]))
head++;
dp[i]=getDP(i,q[head]);
while(head+<tail && getUP(i,q[tail-])*getDOWN(q[tail-],q[tail-])<=getUP(q[tail-],q[tail-])*getDOWN(i,q[tail-]))
tail--;
q[tail++]=i;
}
printf("%d\n",dp[n]);
}
return ;
}

13 / 19 Problem B HDU 2829 Lawrence

斜率DP

设dp[i][j]表示前i点,炸掉j条边的最小值。j<i

dp[i][j]=min{dp[k][j-1]+cost[k+1][i]}

又由得出cost[1][i]=cost[1][k]+cost[k+1][i]+sum[k]*(sum[i]-sum[k])

cost[k+1][i]=cost[1][i]-cost[1][k]-sum[k]*(sum[i]-sum[k])

代入DP方程

可以得出 y=dp[k][j-1]-cost[1][k]+sum[k]^2

x=sum[k].

斜率sum[i]

可以用斜率优化,也可以用四边形不等式优化,四边形不等式我在前面已经写了。

下面是斜率优化的代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXN=;
int a[MAXN];
int sum[MAXN];
int cost[MAXN];//cost[1][i]
int q[MAXN];
int head,tail;
int n,m;
int dp[MAXN][MAXN]; int DP()
{
for(int i=;i<=n;i++)
{
dp[i][]=cost[i];
dp[i][i-]=;
}
for(int j=;j<=m;j++)
{
head=tail=;
q[tail++]=j;
for(int i=j+;i<=n;i++)
{
while(head+<tail)
{
int p1=q[head];
int p2=q[head+];
int x1=sum[p1];
int x2=sum[p2];
int y1=dp[p1][j-]-cost[p1]+sum[p1]*sum[p1];
int y2=dp[p2][j-]-cost[p2]+sum[p2]*sum[p2];
if((y2-y1)<=sum[i]*(x2-x1)) head++;
else break;
}
int k=q[head];
dp[i][j]=dp[k][j-]+cost[i]-cost[k]-sum[k]*sum[i]+sum[k]*sum[k];
while(head+<tail)
{
int p1=q[tail-];
int p2=q[tail-];
int p3=i;
int x1=sum[p1];
int x2=sum[p2];
int x3=sum[p3];
int y1=dp[p1][j-]-cost[p1]+sum[p1]*sum[p1];
int y2=dp[p2][j-]-cost[p2]+sum[p2]*sum[p2];
int y3=dp[p3][j-]-cost[p3]+sum[p3]*sum[p3];
if((y2-y1)*(x3-x2)>=(y3-y2)*(x2-x1))tail--;
else break;
}
q[tail++]=i;
}
}
return dp[n][m];
} int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(scanf("%d%d",&n,&m)==)
{
if(n==&&m==)break;
sum[]=;
cost[]=;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-]+a[i];
cost[i]=cost[i-]+sum[i-]*a[i];
}
printf("%d\n",DP()); }
return ;
}

c2.这个是先求破坏的最大值

/*
* 用dp[i][x]表示前i个点,炸掉x条边可以破坏的最大值
* 答案就是tol-dp[n][m]
* dp[i][x]=max{dp[j][x-1]+sum[j]*(sum[i]-sum[j])} x-1<j<i
* 假设在计算i时,k<j,j比k点优
* dp[k][x-1]+sum[k]*(sum[i]-sum[k])<=dp[j][x-1]+sum[j]*(sum[i]-sum[j])
* 化简得 ( (sum[j]*sum[j]-dp[j][x-1])-(sum[k]*sum[k]-dp[k][x-1]) ) /(sum[j]-sum[k] <=sum[i]
*
* yj=sum[j]*sum[j]-dp[j][x-1] xj=sum[j]
* (yj-yk)/(xj-xk)<=sum[i]
* 右边不等式是递增的
* g[k,j]=(yj-yk)/(xj-xk)
* 上述不等式成立说明j比k优
* 如果k<j<i g[k,j]>g[i,j]那么k可以淘汰
* 如果g[j,i]<sum[i] j可以淘汰
*
*
*/ #include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MAXN=;
int n,m;
int a[MAXN];
int sum[MAXN];
int dp[MAXN][MAXN];
int tol;
int getDP(int i,int x,int j)
{
return dp[j][x-]+sum[j]*(sum[i]-sum[j]);
}
int getUp(int j,int x,int k)
{
return sum[j]*sum[j]-dp[j][x-]-(sum[k]*sum[k]-dp[k][x-]);
}
int getDown(int j,int k)
{
return sum[j]-sum[k];
}
int q[MAXN];
void solve()
{
memset(dp,,sizeof(dp));
int front,rear;
for(int x=;x<=m;x++)
{
rear=front=;
q[rear++]=x;
for(int i=x+;i<=n;i++)
{
while(front+<rear && getUp(q[front+],x,q[front])<=sum[i]*getDown(q[front+],q[front]))
front++;
dp[i][x]=getDP(i,x,q[front]);
while(front+<rear && getUp(i,x,q[rear-])*getDown(q[rear-],q[rear-])<=getUp(q[rear-],x,q[rear-])*getDown(i,q[rear-]))
rear--;
q[rear++]=i;
}
}
printf("%d\n",tol-dp[n][m]);
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(scanf("%d%d",&n,&m)==)
{
if(n== && m==)break;
sum[]=;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-]+a[i];
}
tol=;
for(int i=n;i>;i--)
tol+=a[i]*sum[i-];
solve();
}
return ;
}

1 / 5 Problem C HDU 4528 小明系列故事――捉迷藏
5 / 6 Problem D HDU 1300 Pearls
0 / 42 Problem E HDU 2993 MAX Average Problem
1 / 20 Problem F UVALive 5097 Cross the Wall
5 / 12 Problem G HDU 3045 Picnic Cows
2 / 4 Problem H HDU 3516 Tree Construction
3 / 4 Problem I POJ 1160 Post Office
3 / 5 Problem J POJ 1180 Batch Scheduling
3 / 3 Problem K POJ 2018 Best Cow Fences
2 / 4 Problem L POJ 3709 K-Anonymous Sequence
Problem M POJ 2841 Navigation Game
2 / 2 Problem N POJ 1260 Pearls
2 / 4 Problem O UVA 12594 Naming Babies
3 / 4 Problem P HDU 3480 Division
1 / 1 Problem Q UVALive 6771 Buffed Buffet

[kuangbin带你飞]专题二十 斜率DP的更多相关文章

  1. [kuangbin带你飞]专题二十二 区间DP

            ID Origin Title   17 / 60 Problem A ZOJ 3537 Cake   54 / 105 Problem B LightOJ 1422 Hallowee ...

  2. [kuangbin带你飞]专题二十二 区间DP-B-LightOJ - 1422

    题意大概是这样,第i天必须穿a[i](某一种类)的衣服,你可以套着穿很多件,对于第i天,你有两种操作,一种是脱掉现在的衣服,一种是穿上新的一件,但是你脱掉的衣服,以后不能再穿.问最少需要多少件衣服? ...

  3. [kuangbin带你飞]专题二十二 区间DP-E-POJ - 1651

    区间DP模板题 做区间DP的题目的时候,我们考虑DP[i][j]的含义是什么? 由题意大概是这样的,我们可以从n个数中每次选一个我们以前没选过的数字拿走,需要消耗a[i]*a[i+1]*a[i-1]的 ...

  4. [kuangbin带你飞]专题二十二 区间DP----POJ - 2955

    区间DP标准入门题目. 区间DP大概思路是这样的. 第一层枚举长度,因为我们需要从小区间一步步推到大区间 第二层枚举左端点,那么右端点就定了. 第三层枚举间断点,由间断点合并得到大区间. 这道括号匹配 ...

  5. 「kuangbin带你飞」专题二十 斜率DP

    layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...

  6. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

  7. HDU - 3001 Travelling 状压dp + 三进制 [kuangbin带你飞]专题二

    终于刷完搜索专题了. 题意:给定n个城市,每个城市参观不能超过两次,两个城市之间有道路通过需要花费X,求通过能所有城市的最小花费. 思路:每个城市有三个状态0,1,2,可用三进制存储所有城市的访问状态 ...

  8. HDU1560 DNA sequence IDA* + 强力剪枝 [kuangbin带你飞]专题二

    题意:给定一些DNA序列,求一个最短序列能够包含所有序列. 思路:记录第i个序列已经被匹配的长度p[i],以及第i序列的原始长度len[i].则有两个剪枝: 剪枝1:直接取最长待匹配长度.1900ms ...

  9. 【算法系列学习】[kuangbin带你飞]专题二 搜索进阶 D - Escape (BFS)

    Escape 参考:http://blog.csdn.net/libin56842/article/details/41909459 [题意]: 一个人从(0,0)跑到(n,m),只有k点能量,一秒消 ...

随机推荐

  1. docker 镜像的保存以及导入

    docker 镜像的保存 docker save -o  davename.tar  images docker 镜像的导入 docker  import -  importname < tar ...

  2. CentOS 6使用mutt+msmtp发送邮件

    转:http://www.tuicool.com/articles/YRnQVfq CentOS系统下如果希望向外域发送邮件,需要配置sendmail+dovecot等一系列工具.其实不用这么麻烦,只 ...

  3. vs2012 Nuget错误:“未能解析此远程名称api.nuget.org”

    今天在使用vs2012的Nuget功能向新建MVC项目中添加bootstrap时出现一个错误:“未能解析此远程名称api.nuget.org”: 网上查阅资料得知:nuget.org使用的godadd ...

  4. iOS开发笔记-swift实现iOS数据持久化之归档NSKeyedArchiver

    IOS数据持久化的方式分为三种: 属性列表 (plist.NSUserDefaults) 归档 (NSKeyedArchiver) 数据库 (SQLite.Core Data.第三方类库等 归档(又名 ...

  5. Nokia 的 Scrum标准

    Nokia 的 Scrum标准:• 迭代要有固定时长(被称为“时间盒——timebox”),不能超过六个星期.• 在每一次迭代的结尾,代码都必须经过 QA 的测试,能够正常工作.• Scrum 团队必 ...

  6. chrome比较好用的网站整页(超长网页)截图插件

    chrome比较好用的网站整页(超长网页)截图插件:fireshot capture 试用过比较好用

  7. 简单了解ddos攻击

    1.一种为流量攻击,主要是针对网络带宽的攻击,即大量攻击包导致网络带宽被阻塞,合法网络包被虚假的攻击包淹没而无法到达主机: 2.另一种为资源耗尽攻击,主要是针对服务器主机的攻击,即通过大量攻击包导致主 ...

  8. 功能更强大的格式化工具类 FormatUtils.java

    package com.util; import java.text.DecimalFormat; import java.text.ParseException; import java.text. ...

  9. Linux启动过程详解 (转)

    启动第一步--加载BIOS当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它.这是因为BIOS中包含了CPU的相关信息.设备启动顺序信息.硬盘 ...

  10. 【转】分析Redis架构设计

    一.前言 因为近期项目中开始使用Redis,为了更好的理解Redis并应用在适合的业务场景,需要对Redis设计与实现深入的理解. 我分析流程是按照从main进入,逐步深入分析Redis的启动流程.同 ...