ACM-ICPC (10/14)
动态规划的四个姿势
动态规划要学好,姿势一定要骚,在实战的时候,你将你的转移方程按照以下四种姿势搞一发后,一定会是耳目一新,引来萌妹子的注意~~~哈哈!!!
言归正传了!!!
之所以写动态规划优化,是因为常常在动态规划时,你会发现,就算你很轻易地定义出状态,和找到状态转移方程,但是你有可能面临时间限制。动态规划的优化,主要体现在一维上,一维已经很成熟了,也有很多专家研究这个,关于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)的更多相关文章
- 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 ...
- 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 ...
- ACM ICPC Kharagpur Regional 2017
ACM ICPC Kharagpur Regional 2017 A - Science Fair 题目描述:给定一个有\(n\)个点,\(m\)条无向边的图,其中某两个点记为\(S, T\),另外标 ...
- ACM/ICPC 之 BFS(离线)+康拓展开(TSH OJ-玩具(Toy))
祝大家新年快乐,相信在新的一年里一定有我们自己的梦! 这是一个简化的魔板问题,只需输出步骤即可. 玩具(Toy) 描述 ZC神最擅长逻辑推理,一日,他给大家讲述起自己儿时的数字玩具. 该玩具酷似魔方, ...
- 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 ...
- 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 ...
- 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 ...
- 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 ...
- hduoj 4706 Children'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) ...
- 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) ...
随机推荐
- Xtts v4变化&先决条件&已知问题
V4变化的主要有: 1.这个采购使用简化的命令.源的一个命令(--backup)和目标的一个命令(--restore). 2.此过程只需要在源和目标的$ TMPDIR(res.txt)之间复制 ...
- cmd笔记
批量获取一个文件夹内所有文件的文件名: dir *.png /b >list.txt tree /f >list.txt for /f "delims=" %%a in ...
- mongodb的增删改查
show dbs 显示所有有数据的数据库 use dbname:如use ela; 如果指定的数据库不存在,就会创建,否则就会切到该数据库上. db 显示当前数据库 db.dropDatabase() ...
- 网络编程api bind函数细节 select 细节
struct sockaddr_in bindaddr; bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = htonl(INADDR_ ...
- twitter storm学习 - 安装部署问题汇总
已经碰到的或者将来碰到的关于安装部署方面的问题以及解决方法,先挖个坑 1.提交的topology在admin界面上看emitted始终都是0,查看日志发现有如下错误: worker [ERROR] E ...
- css3之transition、transform、animation比较
css3动画多少都有些了解,但是对于transition.transform.animation这几个属性一直是比较模糊的,所以啊,这里做一个总结,也希望大家都可以对此有一个更好地理解. 其实, ...
- Ubuntu Server 14 配置
语言 在虚拟机中安装了Ubuntu Server. Ubuntu Server只有控制台,没有图形界面.要在控制台下安装中文支持很麻烦.所以直接设置为英文,反正我看得懂. 在安装的时候必须将" ...
- unity摄像机脚本
直接挂载在摄像机上面即可 1.摄像机自由平移 using UnityEngine; using System.Collections; /// <summary> /// 摄像机视角自由移 ...
- MYSQL冷知识——ON DUPLICATE KEY 批量增删改
一 有个需求要批量增删改,并且是混合的,也就是仅不存在才增. 删简单,因为有个deleteStaute之类的字段,删除本质上就是就是一个修改 所以就是实现批量混合增改,然而组长说mysql不支持混合增 ...
- go test遇到的一些问题-command-line-arguments undefined: xxxxx
一 问题是在我写算法题的时候出的,test后缀的文件编译报command-line-arguments undefined: xxxxx 二 没记错,go test是 所有在以_test结尾的源码内以 ...