Noip 2013 Day2 T2 花匠(flower)

Noip 2013 Day2 T2 花匠(flower)

【问题描述】

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

具体而言,栋栋的花的高度可以看成一列整数ℎ1, ℎ2, … , ℎn。设当一部分花被移走后,剩下的花的高度依次为?1, ?2, … , ?m,则栋栋希望下面两个条件中至少有一个满足:

条件 A:对于所有的1 ≤ ? ≤?2,有?2?> ?2?−1 , 同时对于所有的 1 ≤ ? <?2,有?2?

> ?2?+1;

条件 B:对于所有的1 ≤ ? ≤?2,有?2?< ?2?−1,同 时对于所有的1 ≤ ? <?2

,有?2?< ?2?+1。

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

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

【输入】

输入文件为 flower .in。

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

第二行包含n个整数,依次为ℎ1, ℎ2, … , ℎn,表示每株花的高度。

【输出】

输出文件为 flower .out。

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

 

那么这道题做得时候困扰了我很就,我读了很久的题,一直以为是前半部分上升序列,后半部分下降序列,或者互换过来。后来,我写了一个动归,突然,我发现这道题,其实求的是一个波浪形的序列。

目说什么2i,2i-1,2i+1。搞得很难看懂

其实就是说一个数比前一个数小的同时比后一个数大,或者比前一个数大的同时比后一个数小,这样的波浪形序列是满足条件的。

/*

假设当前最优地取到了g[k],并且下一个是波峰,则对于下一个元素k+1:

若g[k]<g[k+1],说明符合题意,可以继续贪心下去。

若g[k]>g[k+1],说明之前若选择g[k+1],则可以取为波峰的情况就更多,于是我们就将最优序列中的g[k]替换成g[k+1]。

同时根据上述贪心,有以下推论:第一个元素是必须要取的。这也是一种很常见的贪心策略。

 

证明:如果不取第一个元素,就必须有取第k个元素,使得最后得到的解最优(假设下一个要去的元素下标为j)。假设从波谷开始,那么有g[k]<g[j]:

若g[1]≤g[j],则不必考虑从g[k]转移,因为[2,k]之间可能会产生更多转移;

若g[1]>g[j],那么我们就可以从波峰开始,最后结果必然是g[j]的最优解+1。

同理可证波峰开始的情况。

 

在缩进了所有相邻元素相同的情况下,不但一定要取最后一个数的贪心可以证明,而且最后的数据整体也就是大波浪形,于是我们在每一个大波浪的谷峰谷底取一下即可。

*/

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cmath>
 5 #include <cstring>
 6 #define INT_MAX_ 0x7fffffff
 7 #define LONG_MAX_ 0x7fffffffffffffffll
 8 #define pi acos(-1)
 9 #define N 100010
10 #define M 1000010
11 using namespace std;
12 
13 inline int read()
14 {
15     int data=0,w=1;
16     char ch=0;
17     while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
18     if(ch=='-') w=-1,ch=getchar();
19     while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
20     return data*w;
21 }
22 
23 inline void write(int x)
24 {
25     if(x<0) putchar('-'),x=-x;
26     if(x>9) write(x/10);
27     putchar(x%10+'0');
28 }
29 
30 int n,top,ans;
31 int hight[N];
32 
33 int main()
34 {
35     freopen("flower.in","r",stdin);
36     freopen("flower.out","w",stdout);
37 
38     n = read();
39     for(int i = 1; i <= n; i++)
40     {
41         hight[i] = read();
42     }
43     for(int i = 1; i <= n; i++) //去重
44     {
45         if(hight[top] != hight[i]) hight[++top] = hight[i];
46     }
47     for(int i = 1; i <= top; i++) //选取
48     {
49         ans += ((i == 1) || (i == top) || (hight[i-1] < hight[i] && hight[i] > hight[i+1]) || (hight[i-1] > hight[i] && hight[i] < hight[i+1]));
50     }
51     write(ans);
52 
53     return 0;
54 }
55 /*
56 题目说什么2i,2i-1,2i+1。搞得很难看懂
57 其实就是说一个数比前一个数小的同时比后一个数大,或者比前一个数大的同时比后一个数小,这样的波浪形序列是满足条件的。
58 */

 

转载于:https://www.cnblogs.com/sin-mo/p/7214366.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值