洛谷P3572题解
这道题实在是一道 毒瘤 题,太坑爹了。那个写 \(deque\) 的题解亲测只有80分,原因 **不言而明 **,这道题居然 丧心病狂 到 卡STL 。
好了,不吐槽了,进入正题
题目分析:
- 这是一道十分 简单 的DP,相信大家也可以很容易地吧DP状态转移方程给推出来。我就献丑给大家推一遍,如有错漏,请留言,谢谢。
- 我们可以定一个函数 \(f(i)\) ,它表示跳到 \(i\) 棵树上去的 \(f(i)\) 的劳累值。由题可知,可以 \(i-v,i-v+1,i-v+2,......i-2,i-1\) 棵树上跳到 \(i\) 棵树,所以可以推出DP状态转移方程 \(f(i)=min\{f(j)+(h(i)>=h(j))\},j\in[i-v,i)\)
- 时间复杂度: \(\Theta(n^2)\) , 空间复杂度: \(\Theta(n)\) 。
code 1:
#include<bits/stdc++.h>
#define Maxn 1000010
#define int long long
using namespace std;
int n;
int h[Maxn];
int p;
int f[Maxn];
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&h[i]);
}
scanf("%lld",&p);
while(p--)
{
memset(f,0,sizeof(f));
int v;
scanf("%lld",&v);
f[1]=0;
for(int i=2;i<=n;i++)
{
int tmp=0x80000000;
for(int j=i-v;j<i;j++)
{
tmp=min(tmp,f[j]+(h[i]>=h[j]));
}
f[i]=tmp;
}
printf("%lld\n",f[n]);
}
return 0;
}
优化 1:
我们考虑用单调队列优化,将其优化成 \(\Theta(n)\) 。作为一个钟爱于STL的 Oler,我选择了方便而又快捷的 \(deque\) 。
我们用单调队列维护 \(f(j)+(h(i)>=h(j))\) 。维护 \(f(j)\) ,将队列中 \(f(j)\) 严格 单调递减,使得队列中的 \(f(j)\) 取出来时永远是最小的;在队尾的 \(f(j)\) 相等时,我们还要将队列中的 \(height(j)\) 进行维护,使得队列中的 \(height(j)\) 单调递增,使得队列中的 \(height(j)\) 的队首取出来永远是是最大的,使得 \((h(i)>=h(j))\) 尽量为0。
去头就简单了,假如 \(j\) 是过期的数据,即 \(j<i-v\) ,我们就把 \(j\) 给 \(pop\) 掉。
code 2:
#include<bits/stdc++.h>
#define Maxn 1000010
#define int long long
using namespace std;
int n;
int h[Maxn];
int p;
int f[Maxn];
struct node
{
int id,v;
};
deque<node>dq;
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&h[i]);
}
scanf("%lld",&p);
while(p--)
{
memset(f,0,sizeof(f));
dq.clear();
int v;
scanf("%lld",&v);
dq.push_back((node){1,0});
for(int i=2;i<=n;i++)
{
while(!dq.empty()&&dq.front().id<i-v)
{
dq.pop_front();
}
f[i]=dq.front().v+(h[i]>=h[dq.front().id]);
while(!dq.empty()&&(dq.back().v>f[i]||(dq.back().v==f[i]&&h[i]>=h[dq.back().id])))
{
dq.pop_back();
}
dq.push_back((node){i,f[i]});
}
printf("%lld\n",f[n]);
}
return 0;
}
优化 2:
题目太过于 毒瘤 ,卡掉了STL,使得STL惨遭TLE,所以我们考虑数组模拟 \(deque\) 。
定义头指针 \(head\) ,尾指针 \(tail\) ,通过移动头尾指针,来模拟 \(deque\) 。 \(pop\_front\) 即为 \(head++\) , \(pop\_back\) 即为 \(tail--\) 。我们很轻松就可以AC了。
注:
STL好用是好用,但一定要注意STL的劣势,那就是在调用函数的时候比数组慢太多。一般来说,STL不会被卡;但难保有如此一道像这一道一样的毒瘤题呢?!
code 3:
#include<bits/stdc++.h>
#define Maxn 1000010
#define int long long
using namespace std;
inline void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n;
int h[Maxn];
int p;
int f[Maxn];
struct node
{
int id,v;
};
node que[Maxn];
signed main()
{
read(n);
for(int i=1;i<=n;i++)
{
read(h[i]);
}
read(p);
while(p--)
{
memset(f,0,sizeof(f));
memset(que,0,sizeof(que));
int v;
read(v);
que[1].id=1;
que[1].v=0;
int head=1;
int tail=2;
for(int i=2;i<=n;i++)
{
while(head<tail&&que[head].id<i-v)
{
head++;
}
f[i]=que[head].v+(h[i]>=h[que[head].id]);
while(head<tail&&(que[tail].v>f[i]||(que[tail].v==f[i]&&h[i]>=h[que[tail].id])))
{
tail--;
}
que[++tail].id=i;
que[tail].v=f[i];
}
printf("%lld\n",f[n]);
}
return 0;
}
最后,给你一个 \(struct\) 封装的 \(deque\) 。
code 4:
#include<bits/stdc++.h>
#define Maxn 1000010
#define int long long
using namespace std;
inline void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n;
int h[Maxn];
int p;
int f[Maxn];
int que_id[Maxn],que_v[Maxn];
struct dque
{
int head,tail;
dque()
{
head=1;
tail=0;
// memset(que,0,sizeof(que));
}
inline bool empty()
{
return head>tail;
}
inline int front_id()
{
return que_id[head];
}
inline int front_v()
{
return que_v[head];
}
inline int back_id()
{
return que_id[tail];
}
inline int back_v()
{
return que_v[tail];
}
inline void pop_front()
{
head++;
}
inline void pop_back()
{
tail--;
}
inline void push_back(int id,int v)
{
que_id[++tail]=id;
que_v[tail]=v;
}
inline void clear()
{
head=1;
tail=0;
}
}dq;
signed main()
{
read(n);
for(int i=1;i<=n;i++)
{
read(h[i]);
}
read(p);
while(p--)
{
memset(f,0,sizeof(f));
dq.clear();
int v;
read(v);
dq.push_back(1,0);
for(int i=2;i<=n;i++)
{
while(!dq.empty()&&dq.front_id()<i-v)
{
dq.pop_front();
}
f[i]=dq.front_v()+(h[i]>=h[dq.front_id()]);
while(!dq.empty()&&(dq.back_v()>f[i]||(dq.back_v()==f[i]&&h[i]>=h[dq.back_id()])))
{
dq.pop_back();
}
dq.push_back(i,f[i]);
}
printf("%lld\n",f[n]);
}
return 0;
}
如果作者有疏漏或错误的地方,请私信给我,或在评论中留言,谢谢。
洛谷P3572题解的更多相关文章
- [洛谷P3376题解]网络流(最大流)的实现算法讲解与代码
[洛谷P3376题解]网络流(最大流)的实现算法讲解与代码 更坏的阅读体验 定义 对于给定的一个网络,有向图中每个的边权表示可以通过的最大流量.假设出发点S水流无限大,求水流到终点T后的最大流量. 起 ...
- 洛谷P5759题解
本文摘自本人洛谷博客,原文章地址:https://www.luogu.com.cn/blog/cjtb666anran/solution-p5759 \[这道题重在理解题意 \] 选手编号依次为: \ ...
- 关于三目运算符与if语句的效率与洛谷P2704题解
题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图.在每一格平原地形上最 ...
- c++并查集配合STL MAP的实现(洛谷P2814题解)
不会并查集的话请将此文与我以前写的并查集一同食用. 原题来自洛谷 原题 文字稿在此: 题目背景 现代的人对于本家族血统越来越感兴趣. 题目描述 给出充足的父子关系,请你编写程序找到某个人的最早的祖先. ...
- 洛谷P2607题解
想要深入学习树形DP,请点击我的博客. 本题的DP模型同 P1352 没有上司的舞会.本题的难点在于如何把基环树DP转化为普通的树上DP. 考虑断边和换根.先找到其中的一个环,在上面随意取两个点, 断 ...
- 【洛谷】题解 P1056 【排座椅】
题目链接 因为题目说输入保证会交头接耳的同学前后相邻或者左右相邻,所以一对同学要分开有且只有一条唯一的通道才能把他们分开. 于是可以吧这条通道累加到一个数组里面.应为题目要求纵列的通道和横列的通道条数 ...
- 洛谷P3572 [POI2014]PTA-Little Bird
P3572 [POI2014]PTA-Little Bird 题目描述 In the Byteotian Line Forest there are nn trees in a row. On top ...
- [洛谷P1972][题解][SDOI2009]HH的项链
别碰我! 自己还是太蒟了…… 看了好久,最后抄参考题解打出来的…… 前面的可能影响后面的,所以按照询问右端点排序 这时候维护一个前缀和数组就可以了, 那么问题又来了,去重? 可以这样,从前往后枚举,如 ...
- 【洛谷P1119题解】灾后重建——(floyd)
这道题告诉我,背的掉板子并不能解决一切问题,理解思想才是关键,比如不看题解,我确实想不清楚这题是弗洛伊德求最短路 (我不该自不量力的说我会弗洛伊德了我错了做人果然要谦虚) 灾后重建 题目背景 B地区在 ...
随机推荐
- 每天学点node系列-stream
在编写代码时,我们应该有一些方法将程序像连接水管一样连接起来 -- 当我们需要获取一些数据时,可以去通过"拧"其他的部分来达到目的.这也应该是IO应有的方式. -- Doug Mc ...
- QDomDocument 读取和编辑xml文件
Qt中几种操作xml的方式 流方式 sax方式 dom方式 初学时,我常常采用流方式读取xml,该方式简单直观,容易理解.之后遇到了需要修改xml并重新写回的情况,流方式就显得捉襟见肘了. sax方式 ...
- python数据库-数据库的介绍及安装(47)
一.数据库的介绍 数据库(Database)是存储与管理数据的软件系统,就像一个存入数据的物流仓库.每个数据库都有一个或多个不同的API接口用于创建,访问,管理,搜索和复制所保存的数据.我们也可以将数 ...
- 关于sql 中delete, truncate,drop的理解与总结
关于文章,本文是在网上查找资料整理而来,方便以后记忆 delete 命令删除的数据可以恢复, truncate 命令删除的数据是不可以恢复的,全删的那种 drop 命令删除的数据不可恢复,连表结构都删 ...
- .NET分布式框架 | Orleans 知多少
引言 公司物联网项目集成Orleans以支持高并发的分布式业务,对于Orleans也是第一次接触,本文就分享下个人对Orleans的理解. 这里先抛出自己的观点:Orleans 是一个支持有状态云生应 ...
- .NET中生成动态验证码
.NET中生成动态验证码 验证码是图片上写上几个字,然后对这几个字做特殊处理,如扭曲.旋转.修改文字位置,然后加入一些线条,或加入一些特殊效果,使这些在人类能正常识别的同时,机器却很难识别出来,以达到 ...
- Git使用小技巧之挑拣合并
先想想一个情况,现在我们有一个功能急需要发布到线上,但是这个功能相关的代码所在的测试分(test)支有很多不应该发布的代码,那么这个时候我们就需要将与这个代码相关的提交选择性的合并到master上并发 ...
- 控制台程序秒变Windows服务(Topshelf)
项目中有些时候需要写服务,一般我们都是先创建控制台程序,测试,运行,成功之后再创建windows服务程序,这样好麻烦啊,有没有简单的控制台程序直接变成Widnows服务,经过查找,找到了Topshel ...
- springboot与springcloud的关系
1 . 问题描述 随着springboot.springcloud的不断迭代升级,开发效率不断提升,越来越多的开发团队加入到spring的大军中,今天用通俗的语言,介绍下什么是springboot,s ...
- redis集群(单机6节点实现)
Redis集群搭建与简单使用 1.介绍安装环境与版本: 1)Redis使用的是Redis-3.2.8版本. 2)用一台虚拟机模拟6个节点,三个master节点,三个slave节点.虚拟机使用CentO ...