动态规划的四个姿势

动态规划要学好,姿势一定要骚,在实战的时候,你将你的转移方程按照以下四种姿势搞一发后,一定会是耳目一新,引来萌妹子的注意~~~哈哈!!!

言归正传了!!!

之所以写动态规划优化,是因为常常在动态规划时,你会发现,就算你很轻易地定义出状态,和找到状态转移方程,但是你有可能面临时间限制。动态规划的优化,主要体现在一维上,一维已经很成熟了,也有很多专家研究这个,关于acm的动态规划优化有很多。下面展示几个常用的奇技淫巧。

  • LIS :​

​ : 以 i 号元素为结尾的最长递增子序列长度。

​ : 最长递增子序列长度为 i 的最小元素值。

在求 ​ 时:只要在 g 数组中二分,同时更新 g 数组。

例题一 :

nyoj 720

分析:类比LIS,同样​ 会TLE,将状态定义稍微优化一点, 先按时间排序,​ 前 i 个元素能达到的最优值,下一个状态起始时间,就可以在前面的状态中二分到这个时间点。细节有两点,一是,排序因子,因为二分是起始时间,因此得按照右端点优先排序,二是,二分手法,应该是upper_bound。

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <algorithm>


using namespace std;

const int maxn = ;

struct Node {
int l,r,v;
bool operator < (const Node & rhs) const {
if(r==rhs.r) return l < rhs.l;
return r < rhs.r;
}
}nodes[maxn];

int n;

int d[maxn];

int upper_bound(int x,int y,int v) {
int m;
while(x<y) {
m = x + (y-x)/;
if(nodes[m].r<=v) x = m+;
else y = m;
}
return x;
}

int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d",&n)!=EOF) {
for(int i = ; i < n; i++)
{
scanf("%d%d%d",&nodes[i].l,&nodes[i].r,&nodes[i].v);
}
sort(nodes,nodes+n);
memset(d,,sizeof(d));
d[] = nodes[].v;
for(int i = ; i < n; i++) {
d[i] = max(d[i-],nodes[i].v);
int k = upper_bound(,i,nodes[i].l);
if(k>&&nodes[k-].r<=nodes[i].l)
d[i] = max(d[i],d[k-]+nodes[i].v);
}
printf("%d\n",d[n-]);

}
return ;
}

还记得括号匹配吗?

Google Code jam 2016 Round3 A;就是一道裸的括号匹配。成功匹配得10分,失败得5分。给定一个序列,求最大得分。因为暂时我电脑连不上Google,原题就不贴了。做法很简单,维护一个栈。

例题二: pku2559

题意:求最大子矩阵面积。

此题是三倍经验题哦,还有一个在51Nod,和一场个人赛GYM上出现过(当时有大佬用KMP搞的);这里利用栈来做到​

分析:无非就是要快速求出一个数字作为最小值(最大值)的左右端点区间。暴力​ 实在受不了,这里利用单调栈一下子就降到​ 。

维护一个按照高度递增的单调栈,当新加入的矩形破坏了单调栈的单调性,说明一件事情,就是栈顶元素的生命周期已经结束了,他作为最小值的左右端点已经确定。


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <iostream>
#include <algorithm>

using namespace std;


const int maxn = 1e5+;
int h[maxn];

int main()
{
//freopen("in.txt","r",stdin);
int n;
while(scanf("%d",&n),n) {

for(int i = ; i <= n; i++) scanf("%d",&h[i]);

stack<int> S;
S.push();h[++n] = ;
long long ans = ;
for(int i = ; i <= n; i++) {
while(h[i]<h[S.top()]) {
long long a = h[S.top()];
S.pop();
long long b = i - S.top() - ;
if(ans < a*b) ans = a*b;
}
S.push(i);
}

printf("%lld\n",ans);
}
return ;
}

例题三:pku 2823

题意:滑动窗口最小值(最大值)

分析:如果你想不到很好的办法,也可以直接上RMQ,​

现在,用​ 的解法~~~

维护一个单调自增的队列,同样,如果新加入的数字破坏了队列的单调性,说明队尾的数字将永远不会是这k个数字中的最小值,他已经没用了。

算法具体做法,可能我写的比较渣,大佬很好像合起来写的。

首先,将前k个数字入队列,队首元素就是最小值。

然后加入新的数字,如果破坏了单调性,弹出队尾数字,此时,又一个最小值求出来了,但是这个最小值还要检验一下,是否他还在下一个区间里面。


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 1e6+;
int a[maxn];

int main()
{
//freopen("in.txt","r",stdin);
int n,k; cin>>n>>k;

for(int i = ; i < n; i++) scanf("%d",&a[i]);
deque<int> minq;
deque<int> maxq;

for(int i = ; i < k; i++) {
while(!minq.empty()&&(a[i]<a[minq.back()]) ) {
minq.pop_back();
}
while(!maxq.empty()&&(a[i]>a[maxq.back()])) {
maxq.pop_back();
}
minq.push_back(i);
maxq.push_back(i);
}

printf("%d ",a[minq.front()]);

if(minq.front()==)
minq.pop_front();

for(int i = k; i < n; i++) {
while(!minq.empty()&&(a[i]<a[minq.back()])) {
minq.pop_back();
}
minq.push_back(i);
printf("%d ",a[minq.front()]);
if(minq.front()<=i-k+)
minq.pop_front();
}
puts("");


printf("%d ",a[maxq.front()]);

if(maxq.front()==)
maxq.pop_front();

for(int i = k ; i < n; i++) {
while(!maxq.empty()&&(a[i]>a[maxq.back()])) {
maxq.pop_back();
}
maxq.push_back(i);
printf("%d ",a[maxq.front()]);
if(maxq.front()<=i-k+)
maxq.pop_front();
}
puts("");

return ;
}

例题四:bzoj 1911

分析:很容易想到类似于LIS的转移。但是数据范围有​ ,​ 是肯定过不了的。然而,只要稍加转换,

可以发现他是一个斜率公式,然后分析,斜率是凸函数,还是凹函数,只要看符号,这里是大于号,上凸函数中间的点的斜率是不起作用的,那么你应该维护一个斜率单调递增的栈(实际操作中是队列)。

那么最优值在哪里呢?

根据斜率最大,即应该是相切处,那么这时候,你需要根据凹函数的特点了,从前往后遍历,当斜率大于右边,则到达了当前点了。然后加入此节点,也需要维护单调队列的凹函数性质。

关于斜率DP,也是每一个大佬有一种写法,主要不同点在于队列中的点个数上,我习惯于队列中必须有一个结点(有的要两个点),主要是有一个坐标原点。可以实现包含所有可选择区间。具体细节还得自己动手才能发现。


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
const int maxn = 1e6+;

long long a,b,c;
long long x[maxn];
long long sum[maxn];
long long d[maxn];
double slope(int i,int j)
{
double up = d[i]-d[j]+a*(sum[i]*sum[i]-sum[j]*sum[j])+b*(sum[j]-sum[i]);
double down = *a*(sum[i]-sum[j]);
return up/down;
}
int l,r,q[maxn];
int n;


int main()
{
freopen("in.txt","r",stdin);
scanf("%d%lld%lld%lld",&n,&a,&b,&c);

sum[] = ;
for(int i = ; i <= n; i++) {
scanf("%lld",&x[i]);
sum[i] = sum[i-] + x[i];
}

deque<int> deq;

for(int i = ; i <= n; i++) {

double xl = slope(q[l],q[l+]);
while(l<r&&slope(q[l],q[l+])<sum[i]) {
l++;
}
int now = q[l];
d[i]=d[now]+a*(sum[i]-sum[now])*(sum[i]-sum[now])+b*(sum[i]-sum[now])+c;
while(l<r&&slope(q[r-],q[r])>slope(q[r],i)) r--;
q[++r] = i;

}

printf("%lld\n",d[n]);


return ;
}

到这里DP优化已经聊的差不多了。其实你会发现我都是1D/1D方程,而实战中也有很多2D/0D方程,比如LCS。

但是他们的优化思路,是还有待大牛研究的课题。

ACM-ICPC (10/14)的更多相关文章

  1. 2016 ACM/ICPC Asia Regional Qingdao Online 1001/HDU5878 打表二分

    I Count Two Three Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  2. 2016 ACM/ICPC Asia Regional Qingdao Online(2016ACM青岛网络赛部分题解)

    2016 ACM/ICPC Asia Regional Qingdao Online(部分题解) 5878---I Count Two Three http://acm.hdu.edu.cn/show ...

  3. ACM ICPC Kharagpur Regional 2017

    ACM ICPC Kharagpur Regional 2017 A - Science Fair 题目描述:给定一个有\(n\)个点,\(m\)条无向边的图,其中某两个点记为\(S, T\),另外标 ...

  4. ACM/ICPC 之 BFS(离线)+康拓展开(TSH OJ-玩具(Toy))

    祝大家新年快乐,相信在新的一年里一定有我们自己的梦! 这是一个简化的魔板问题,只需输出步骤即可. 玩具(Toy) 描述 ZC神最擅长逻辑推理,一日,他给大家讲述起自己儿时的数字玩具. 该玩具酷似魔方, ...

  5. ACM ICPC 2015 Moscow Subregional Russia, Moscow, Dolgoprudny, October, 18, 2015 D. Delay Time

    Problem D. Delay Time Input file: standard input Output file: standard output Time limit: 1 second M ...

  6. hduoj 4715 Difference Between Primes 2013 ACM/ICPC Asia Regional Online —— Warmup

    http://acm.hdu.edu.cn/showproblem.php?pid=4715 Difference Between Primes Time Limit: 2000/1000 MS (J ...

  7. hduoj 4712 Hamming Distance 2013 ACM/ICPC Asia Regional Online —— Warmup

    http://acm.hdu.edu.cn/showproblem.php?pid=4712 Hamming Distance Time Limit: 6000/3000 MS (Java/Other ...

  8. hduoj 4707 Pet 2013 ACM/ICPC Asia Regional Online —— Warmup

    http://acm.hdu.edu.cn/showproblem.php?pid=4707 Pet Time Limit: 4000/2000 MS (Java/Others)    Memory ...

  9. hduoj 4706 Children&#39;s Day 2013 ACM/ICPC Asia Regional Online —— Warmup

    http://acm.hdu.edu.cn/showproblem.php?pid=4706 Children's Day Time Limit: 2000/1000 MS (Java/Others) ...

  10. 2016 ACM/ICPC Asia Regional Shenyang Online 1009/HDU 5900 区间dp

    QSC and Master Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

随机推荐

  1. js的apply和call

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. .reverse ,join,split区分

    * 1:arrayObject.reverse() * 注意: 该方法会改变原来的数组,而不会创建新的数组. * 2:arrayObject.join() * 注意:join() 方法用于把数组中的所 ...

  3. PIXI 下落文字消除(3)

    图片示例,简陋的图,记录下落过程, 1.创建应用实例并添加到DOM元素上. (会看到一个黑色画布,没有任何元素,接下来会在画布上创建文字) 2.创建  TextStyle 用来设置要显示字体样式 3. ...

  4. 网络编程api bind函数细节 select 细节

    struct sockaddr_in bindaddr; bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = htonl(INADDR_ ...

  5. Oracle RAC集群搭建(五)--oracle部署

    01,配置好环境 节点01--node1 ORACLE_BASE=/oracle/app/oracle ORACLE_HOME=$ORACLE_BASE/product//db_1 ORACLE_SI ...

  6. mysql 命令笔记

    添加密码 mysqladmin -uroot -p password 123456 创建用户只能在10.0.0.0网段下访问数据库grant select,create,insert,update o ...

  7. rancher1.X+docker+k8s搭建容器管理集群

    一, 环境准备 服务器 Linux k8s-m -.el7.x86_64 #1 SMP Fri Apr 20 16:44:24 UTC 2018 x86_64 x86_64 x86_64 GNU/Li ...

  8. mac下安装win7虚拟机和导入linux虚拟机

  9. 深入理解jQuery插件开发【转】

    如果你看到这篇文章,我确信你毫无疑问会认为jQuery是一个使用简便的库.jQuery可能使用起来很简单,但是它仍然有一些奇怪的地方,对它基本功能和概念不熟悉的人可能会难以掌握.但是不用担心,我下面已 ...

  10. jquery 获取easyui combobox选中的值、赋值

    jquery easyui combobox 控件支持单选和多选 1.获取选中的值 $('#comboboxlist').combobox('getValue');  //单选时 $('#combob ...