DP练习题——洛谷P1970花匠
题目描述:
花匠栋栋种了一排花,每株花都有自己的高度。花儿越长越大,也越来越挤。栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致。
具体而言,栋栋的花的高度可以看成一列整数\(h_1,h_2,...,h_n\)。设当一部分花被移走后,剩下的花的高度依次为\(g_1,g_2,...,g_m\),则栋栋希望下面两个条件中至少有一个满足:
条件 \(A\):对于所有\(g_{2i}>g_{2i-1},g_{2i}>g_{2i+1}\)
条件 \(B\):对于所有\(g_{2i}<g_{2i-1},g_{2i}<g_{2i+1}\)
注意上面两个条件在\(m=1\)时同时满足,当\(m > 1\)时最多有一个能满足。
请问,栋栋最多能将多少株花留在原地。
输入输出格式:
输入格式:
第一行包含一个整数\(n\),表示开始时花的株数。
第二行包含\(n\)个整数,依次为\(h_1,h_2,...,h_n\),表示每株花的高度。
输出格式:
一个整数\(m\),表示最多能留在原地的花的株数。
输入输出样例:
输入样例:
5
5 3 2 1 2
输出样例:
3
题目分析:
简单理解一下题意:
大体就是说要求留在原地的花满足:序号为\(2\)的倍数的花是左右两盆花中最高或者是最矮的
解法一:
思路:
既然是\(DP\)的题,那么我们先考虑贪心(其实是为了纪念\(lz\)):
说句闲话:学习\(DP\)的最好方法是什么??
贪心!!!
好了好了,说正经的。
不过还是要吐槽这道题的算法标签,竟然没人评贪心(也不知道\(lz\)评了没有)
我们可以发现,这道题就是对一个有波动的函数进行简化,我们可以举两个例子,一个是样例:
我们可以把这个图像看做一个具有两个单调区间的函数图像,我们只能去单调区间两端的点构成新的序列,也就是说我们最多能保留三盆花
另一个是从讨论版里找来的神仙数据:
有了上面的分析,我们可以很轻易地找出\(3\)个单调区间,也就是说最多有\(4\)盆花能够被留下
算法:
根据两组数据,我们可以得到这样一个算法:
扫描所有花的高度,从而得出增减区间的个数\(w\),输出\(w+1\)
代码实现:
#include<cstdio>
#include<iostream>
using namespace std;
inline int read()
{
int F=1,num=0;
char c=getchar();
while(!isdigit(c)){if(c=='-') F=-1; c=getchar();}
while(isdigit(c)){num=num*10+c-'0'; c=getchar();}
return num*F;
}
int h[10000010];
int n;
int ans=1;//考虑到函数的左区间
int direction;
int main()
{
n=read();
for(int i=1;i<=n;++i)
h[i]=read();//读入
if(h[2]>=h[1]) direction=1;//1表示增区间,0表示减区间 ,因为前两个是默认都选的,所以在这里加上了等号
for(int i=1;i<=n;++i)//我知道可以边读入边判断,但是我愿意,你管着吗??
{
if(i==n)
{
ans++;//考虑到函数的右区间,当到了右区间时答案直接加一并且跳出循环
break;
}
if(h[i+1]>h[i])
{
if(direction==0)//如果突然进入到增区间,就标记为增区间并且答案加一
{
ans++;
direction=1;
}
}
if(h[i+1]<h[i])
{
if(direction==1)//如果突然进入到减区间,就标记为减区间并且答案加一
{
ans++;
direction=0;
}
}
}
printf("%d",ans);//输出答案
return 0;
}
解法二:
思路:
当然是已经哭晕在厕所的\(DP\)啦
\(dp[i][0]\)表示在\(i\)处上升时的最大盆数,\(dp[i][1]\)表示在\(i\)处下降时的最大盆数
直接得到状态转移方程
\(if(a[i]>a[i-1])\space\space\space dp[i][0]=dp[i-1][1]+1;\\if(a[i]<a[i-1])\space\space\space dp[i][1]=dp[i-1][0]+1;\\dp[i][0]=max(dp[i][0],dp[i-1][0]);\\dp[i][1]=max(dp[i][1],dp[i-1][1]);\)
解释一下:
当\(a[i]\)是上升的时候,将上升时的最大盆数更新为上一盆下降时的最大盆数+\(1\),并且用这两种状态的最大值来维护\(dp[i][0]\),表示满足条件\(B\)
当\(a[i]\)是下降的时候,将下降时的最大盆数更新为上一盆上升时的最大盆数+\(1\),并且用这两种状态的最小值来维护\(dp[i][1]\),表示满足条件\(A\)
如果还不能理解就画个图,手推一下233~~
算法:
就是将\(dp[1][1]\)和\(dp[1][0]\)都更新为\(1\),然后从\(2\)开始跑一遍循环,\(CV\)上面的方程就结束了
Talk is cheap,show me the code:
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=101000;
int dp[maxn][2],a[maxn];
int n;
inline int read()
{
int F=1,num=0;
char c=getchar();
while(!isdigit(c)){if(c=='-') F=-1; c=getchar();}
while(isdigit(c)){num=num*10+c-'0'; c=getchar();}
return F*num;
}
int main()
{
n=read();
dp[1][0]=1;dp[1][1]=1;
for(int i=1;i<=n;i++) a[i]=read();
for(int i=2;i<=n;i++)
{
if(a[i]>a[i-1]) dp[i][0]=dp[i-1][1]+1;
if(a[i]<a[i-1]) dp[i][1]=dp[i-1][0]+1;
dp[i][0]=max(dp[i][0],dp[i-1][0]);
dp[i][1]=max(dp[i][1],dp[i-1][1]);
}
printf("%d\n",max(dp[n][1],dp[n][0]));
return 0;
}
结语:
贪心大法真的好诶(逃
DP练习题——洛谷P1970花匠的更多相关文章
- 洛谷 P1970 花匠 —— DP
题目:https://www.luogu.org/problemnew/show/P1970 普通的DP,f[i][0/1] 表示 i 处处于较小或较大的长度: 注意:1.树状数组向后 query 时 ...
- 洛谷P1970 花匠(dp)
题意 题目链接 Sol 直接用\(f[i][0/1]\)表示到第\(i\)个位置,该位置是以上升结尾还是以下降结尾 转移的时候只需枚举前一个即可 #include<cstdio> #inc ...
- [NOIP2013] 提高组 洛谷P1970 花匠
题目描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定 把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希 望剩下的花排列得比较别致. 具 ...
- 洛谷 P1970 花匠
题目描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致. 具体而 ...
- 洛谷——P1970 花匠
https://www.luogu.org/problem/show?pid=1970 题目描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定 把这排中的一部分花移走, ...
- 洛谷P1970 花匠
传送门 首先可以知道,如果一个序列是连续上升的,那么只需要取这一个序列中最高的元素即可,因为取其它的不能保证大于后面的.连续下降的序列同理.而这些恰好就是波峰和波谷. 所以遇到 $ j $ 比之前的 ...
- 【线型DP】洛谷P2066 机器分配
[线型DP]洛谷P2066 机器分配 标签(空格分隔): 线型DP [题目] 题目描述 总公司拥有高效设备M台,准备分给下属的N个分公司.各分公司若获得这些设备,可以为国家提供一定的盈利.问:如何分配 ...
- 洛谷P1970 [NOIP2013提高组Day2T2] 花匠
P1970 花匠 题目描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定 把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希 望剩下的花排 ...
- Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装
[洛谷P2515][HAOI2010]软件安装 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得 ...
随机推荐
- python 模块使用
模块使用 定义:模块就像一个工具包一样,里面有很多工具(函数.类),使用时需要通过import导入. 分类: 标准库:random.sys.os.time 第三方:就是好人已经写好的特定功能的模块,你 ...
- 第二十篇 jQuery 初步学习2
jQuery 初步学习2 前言: 老师这里啰嗦一下,因为考虑到一些同学,不太了解WEB前端这门语言.老师就简单的说一下,写前端,需要什么:一台笔记本.一个文本编辑器.就没啦!当然,写这门语言, ...
- SQL-Serverの自動採番(IDENTITY値)の取得・リセット
システムに必要なテーブルで.自動的に番号を振っていくものが必要なときがあります. たとえば.各種の伝票データの伝票番号の様なものです. プログラム処理上.データを登録した直後に.自動採番された値を取得 ...
- Nginx如何配置反向代理
server { listen 80; server_name 代理域名; location / { proxy_pass 应用域名:应用端口; proxy_set_header Host $host ...
- LINUX任意精度计算器BC用法
[用途说明] Bash内置了对整数四则运算的支持,但是并不支持浮点运算,而bc命令可以很方便的进行浮点运算,当然整数运算也不再话下.手册页上说bc是An arbitrary precision cal ...
- linux上如何安装mysql
下载rpm包: wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 安装rpm:rpm -ivh mysql-com ...
- 一,python简介 笔记
python历史 1,1989年圣诞节,Guido von Rossum开始编写python语言编译器 2,1991年2月,第一个python编译器诞生,是c语言实现的,后面又出现了c#和java版本 ...
- 能ping通某网页,但无法访问网页的处理
cmd----->netsh winsock reset 用以重置Winsock目录,是网络环境初始化,解决一些奇怪的问题
- PHP5.3x被弃用的函数及代替方法
今天阳光明媚,万里无云,小记一下php5.3x被弃用的部分函数及代替方法 下面列举了部分被弃用的函数:call_user_method():(使用 call_user_func() 替代)call_u ...
- 火狐插件simple timer 定时打开指定网页
今天我要介绍的是火狐浏览器一款插件:Simple Timer,该插件是火狐一个可以添加计时器和定时提醒功能插件,该插件的主要作用就是当你的设置在某一个时刻提醒时,插件会自动弹出通知,并且自动打开你想要 ...

