Description

花匠栋栋种了一排花,每株花都有自己的高度。花儿越长越大,也越来越挤。栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致。

具体而言,栋栋的花的高度可以看成一列整数h1,h2,…,hnh_1, h_2, … , h_n。设当一部分花被移走后,剩下的花的高度依次为g1,g2,…,gmg_1, g_2, … , g_m,则栋栋希望下面两个条件中至少有一个满足:

条件 A:对于1≤i≤m/21≤i≤m/2,有g2i>g2i−1g_{2i}>g_{2i-1},同时对于所有的1≤i<m/21≤i,有g2i>g2i+1g_{2i}>g_{2i+1};

条件 B:对于1≤i≤m/21≤i≤m/2,有g2i<g2i−1g_{2i},同时对于1≤i<m/21≤i,有g2i<g2i+1g_{2i}

注意上面两个条件在m = 1时同时满足,当m > 1时最多有一个能满足。

请问,栋栋最多能将多少株花留在原地。

Input

输入的第一行包含一个整数 n,表示开始时花的株数。

第二行包含 n 个整数,依次为h1,h2,…,hnh_1, h_2,… , h_n,表示每株花的高度。

Output

输出一行,包含一个整数 m,表示最多能留在原地的花的株数。

Sample Input

5

5 3 2 1 2

Sample Output

3

Data Constraint

对于 20%的数据,n ≤ 10;

对于 30%的数据,n ≤ 25;

对于 70%的数据,n ≤ 1000,0 ≤ hih_i ≤ 1000;

对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤ hih_i ≤ 1,000,000,所有的hih_i随机生成,所有随机数服从某区间内的均匀分布。


思路 1
可以用类似于最长xx子序列的思想来做,时间复杂度为O(n2)O(n^2):

    std::vector<INT> height(n + 1);std::vector<INT> fA(n + 1, 1);std::vector<INT> fB(n + 1, 1);for (int i = 1; i <= n; i++){height[i] = readIn();for (int j = 1; j < i; j++){if (fA[j] & 1){if (height[i] > height[j])fA[i] = std::max(fA[i], fA[j] + 1);}else{if (height[i] < height[j])fA[i] = std::max(fA[i], fA[j] + 1);}ans = std::max(ans, fA[i]);if (fB[j] & 1){if (height[i] < height[j])fB[i] = std::max(fB[i], fB[j] + 1);}else{if (height[i] > height[j])fB[i] = std::max(fB[i], fB[j] + 1);}ans = std::max(ans, fB[i]);}}

思路 2

可以用线段树加速DP:

    SegTre stA1; //A为奇数的SegTre stA2; //A为偶数的SegTre stB1; //B为奇数的SegTre stB2; //B为偶数的for (int i = 1; i <= n; i++){INT height = readIn() + 2;INT valA1 = stA1.query(1, height - 1) + 1; //偶数INT valA2 = stA2.query(height + 1) + 1; //奇数INT valB1 = stB1.query(height + 1) + 1; //偶数INT valB2 = stB2.query(1, height - 1) + 1; //奇数if (!(valA1 & 1)){ans = std::max(ans, valA1);stA2.set(height, valA1);}if (valA2 & 1){ans = std::max(ans, valA2);stA1.set(height, valA2);}if (!(valB1 & 1)){ans = std::max(ans, valB1);stB2.set(height, valB1);}if (valB2 & 1){ans = std::max(ans, valB2);stB1.set(height, valB2);}}

然而以上两种思路的状态转移方程分了A,B两种情况,要判断4次,太渣了,以至于使用线段树也只能过9个点。

应该采用这个状态转移方程:(f[i]代表最高点,g[i]代表较低点)

f[i]=max1≤j<i且aj<ai{g[j]+1}

f[i]=\underset {1\le j \lt i且a_j\lt a_i}{max}\{g[j] + 1\}

g[i]=max1≤j<i且aj>ai{f[j]+1}

g[i]=\underset {1\le j \lt i且a_j\gt a_i}{max}\{f[j] + 1\}
因为A,B其实是一种情况,要把它们看做锯齿。

void SuperDP()
{SegTre f; //较大SegTre g; //较小for(int i = 1; i <= n; i++){INT height = readIn() + 2;INT valG = f.query(height + 1) + 1;INT valF = g.query(1, height - 1) + 1;ans = std::max(ans, std::max(valF, valG));f.set(height, valF);g.set(height, valG);}
}

思路 2
那为什么不直接找锯齿呢。。。或者说,找所有在单调上升和单调下降之间的点。
首先,我们要先把连续的相同高度的花删掉。然后我们从头到尾扫过去,遇到了拐点就让答案+1,最后算上两个端点就好了。
动归固然跪,分析大法好。

参考代码

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
using std::cin;
using std::cout;
using std::endl;
typedef long long INT;
inline INT readIn()
{bool minus = false;INT a = 0;char ch = getchar();while(!(ch == '-' || ch >= '0' && ch <= '9')) ch = getchar();if(ch == '-'){minus = true;ch = getchar();}while(ch >= '0' && ch <= '9'){a *= 10;a += ch;a -= '0';ch = getchar();}if(minus) a = -a;return a;
}const INT maxn = 100005;
INT n;
INT N;
INT height[maxn];
INT ans;void run()
{n = readIn();ans = 1;INT pre = -1;for(int i = 1; i <= n; i++){INT input = readIn();if(input == pre) continue;height[++N] = input;pre = input;}if(N >= 2) ans++; //如果长度大于等于2的话就有两个端点for(int i = 2; i <= N - 1; i++){if(height[i - 1] < height[i] && height[i] > height[i + 1]) ans++;else if(height[i - 1] > height[i] && height[i] < height[i + 1]) ans++;}cout << ans << endl;
}int main()
{run();return 0;
}

NOIP 2013 Senior 5 - 摆花相关推荐

  1. [NOIP 2013提高组]转圈游戏 题解

    这题在洛谷上是道黄题,即[普及/提高-] 所以虽然是提高组的,但是其实挺简单的. 我们来看下题面: [NOIP 2013]转圈游戏 刚看到题面作为一个蒟蒻感觉它都不配做黄题,但是直到我看清楚了后发现它 ...

  2. NOIP 2013 提高组 货车运输

    描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多 ...

  3. NOIP 2013 普及组初赛试题

    第 1 题 一个 32 位整型变量占用(A)个字节. A. 4 B. 8 C. 32 D. 128 常识题,每个32 位整型变量占4个字节 第 2 题 二进制数 11.01 在十进制下是(A). A. ...

  4. [NOIp 2013]货车运输

    Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重 ...

  5. Noip 2013 练习

    转圈游戏 传送门 Solution 快速幂 Code //By Menteur_Hxy #include <cstdio> #include <cstdlib> #includ ...

  6. NOIP 2013 day1

    tags: 模拟 快速幂 逆序对 树状数组 归并排序 最小生成树 lca 倍增 categories: 信息学竞赛 总结 tex live 2017.iso 转圈游戏 火柴排队 货车运输 转圈游戏 s ...

  7. 水题 逆序对 NOIP 2013 火柴排队

    题目如下 题目描述 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为: ,其中 a ...

  8. 「NOIP 2013」 货车运输

    题目链接 戳我 \(Solution\) 这一道题直接用\(kruskal\)重构树就好了,这里就不详细解释\(kruskal\)重构树了,如果不会直接去网上搜就好了.接下来讲讲详细过程. 首先构建\ ...

  9. NOIP 2013 day2

    tags: 模拟 贪心 搜索 动态规划 categories: 信息学竞赛 总结 积木大赛 花匠 华容道 积木大赛 Solution 发现如果一段先单调上升然后在单调下降, 那么这一块的代价是最高的减 ...

最新文章

  1. RxJava 教程第一部分:为何使用RxJava
  2. python调参工作都是干啥的_xgboost原理及调参方法-通俗易懂版本
  3. ad电阻原理图_【雕爷学编程】Arduino动手做(2)---光敏电阻模块
  4. android开发我的新浪微博客户端-登录页面UI篇(4.1)
  5. 【华为云技术分享】关于Linux下Nginx的安装及配置
  6. Crowdin 使用指南
  7. 项目中的每个层的理念是什么?
  8. 安卓编解码的分辨率问题
  9. 项目管理工具——Jira使用和配置
  10. 红帽linux中文语言包,英文 RedHat AS5 中文语言包安装
  11. JAVA_判断日期是否为工作日(排除节假日和调整周末上班)
  12. 日本京瓷株式会社会长-稻盛和夫寄语汇总
  13. Linux内核kernel panic机制浅析
  14. 程序猿给娃取名的正确姿势
  15. 爬取 bilibili 弹幕数据
  16. 固态硬盘和机械硬盘的区别
  17. python中pass语句的作用是什么_简述 Python 中 pass 语句的作用。
  18. 无线降噪蓝牙耳机对比:NANK南卡和苹果AirPods Pro哪个好用?
  19. [Pytorch 常用函数] 激活函数Relu, Leaky Relu
  20. Revit教程-Revit包络如何控制墙体面层

热门文章

  1. Linux正则表达式(基于awk)
  2. 从事金融行业需要考什么证书?
  3. iFFT逆运算-使用软件无线电GQRX显示简笔画信号
  4. [直播]2021 信创“大比武”基础办公应用开发赛道 - 总决赛
  5. 表格最多两行,超出显示...移入可以查看超出的详情。
  6. 小猴子跌落山崖之 linear、ease、ease-in
  7. 博士如何出牛文章?浅谈SCI论文发表全攻略
  8. 使用python随机画几何图形(矩形、圆形、三角形...)
  9. python100例讲解-【学习笔记】python100例
  10. 【2069】糖果游戏