【NOIP】2013提高组 花匠(摆花)

【算法】DP||贪心

【题解】

(1)动态规划:

令f[i][0..1]为两种条件前i株花的最大保留数量,状态转移方程:

f[i][0]=max(f[j][1]+1) (j=i-1...1)(h[i]>h[j])

f[i][1]=max(f[j][0]+1) (j=i-1...1)(h[i]<h[j])

初始化:f[i][0]=f[i][1]=1,这样时间复杂度是O(n^2)。

由于题目的数据范围中有一句话:所有的h_i随机生成,所有随机数服从某区间内的均匀分布。

所以加个优化,因为f[i][0](i=1...n)和f[i][1](i=1...n)存在单调性(不下降),即f[x][0]>=f[y][0](x>y),f[x][1]>=f[y][1](x>y)

所以在状态转移枚举j时,当f[i][0]和f[i][1]都>1(大于初始值)时,就可以不用再向前找j而是直接跳向下一个i。

优化后可以通过所有数据(AC)。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100010;
int f[maxn][2],h[maxn],n;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
     {
         scanf("%d",&h[i]);
         f[i][0]=1;f[i][1]=1;
     }
    for(int i=2;i<=n;i++)
     for(int j=i-1;j>=1;j--)
      {
          if(h[i]>h[j])f[i][1]=max(f[i][1],f[j][0]+1);
          if(h[i]<h[j])f[i][0]=max(f[i][0],f[j][1]+1);
          if(f[i][0]>1&&f[i][1]>1)break;//剪枝优化,单调性 
      }
    printf("%d",max(f[n][0],f[n][1]));
    return 0;
}
View Code

(2)贪心

学自:http://tieba.baidu.com/p/2714238975

先把序列中相邻的相同元素删剩一个(去重),然后在序列中寻找所有满足a[i-1]<a[i]>a[i+1]或者a[i-1]>a[i]<a[i+1]的元素,这样的元素个数即答案。

解释:去重后的序列就是在不断波动,因此这两种元素一定会交替出现,而相邻的这两种元素中间的一段,这一段必然是单调递增或者单调递减的,因此最多选择两个元素,而选择两个端点就必然是最优的。

这样时间复杂度是O(n)。

#include<cstdio>
int a[100010],b[100010],n,ans,tot;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    b[(tot=1)]=a[1];
    for(int i=2;i<=n;i++)
     if(a[i]!=b[tot])b[++tot]=a[i];
    ans=2;//1和n 
    for(int i=2;i<tot;i++)
     if((b[i]<b[i-1]&&b[i]<b[i+1])||(b[i]>b[i-1]&&b[i]>b[i+1]))ans++;
    if(tot==1)ans=1;if(tot==0)ans=0;
    printf("%d",ans);
    return 0;
}
View Code

 

posted @ 2016-08-13 09:13  ONION_CYC  阅读(624)  评论(0编辑  收藏  举报