zoukankan      html  css  js  c++  java
  • [noip2013 d2t2]花匠

    题意:给定一串数,求最多可留下多少个呈波浪状排列的数

    对于30%:最最朴素的暴力

    对于70%:考虑O(n²) dp

    设f[i][1]为以第i个数为结尾的序列,满足条件A的最优解;f[i][2]为以第i个数为结尾的序列,满足条件B的最优解

    题目给出的两个条件,其实为状态转移提供了思路

    不难得出方程

    f[i][1]=max(f[j][2]+1)(j<i,h[i]>h[j])

    f[i][2]=max(f[j][1]+1)(j<i,h[i]<h[j])

    初始f[i][1]=f[i][2]=1;

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<ctype.h>
     5 using namespace std;
     6 const int maxn=100100;
     7 int f[maxn][3],h[maxn];
     8 int read(){
     9     int x=0;
    10     char ch=getchar();
    11     while (!isdigit(ch)) ch=getchar();
    12     while (isdigit(ch)){
    13         x=x*10+ch-'0';
    14         ch=getchar();
    15     }
    16     return x;
    17 }
    18 int main(){
    19     int n=read();
    20     for (int i=1;i<=n;i++){
    21         h[i]=read();
    22         f[i][1]=f[i][2]=1;
    23     }
    24     int ans=1;
    25     for (int i=1;i<=n;i++){
    26         for (int j=1;j<i;j++){
    27             if (h[i]>h[j]) f[i][1]=max(f[i][1],f[j][2]+1);
    28             if (h[i]<h[j]) f[i][2]=max(f[i][2],f[j][1]+1);
    29         }
    30         ans=max(ans,max(f[i][1],f[i][2]));
    31     }
    32     printf("%d
    ",ans);
    33     return 0;
    34 }
    View Code

    然而这并不足以通过所有测试,n=10w的规模让我们考虑优化

    观察可知 f数组是单调递增的,所以我们可以倒序查找,找到上一个有解的f就退出

    亦可修改方程,每个点都保存此前的最优值,令i只和i-1有关

    两种方法的时间均可视为O(n)级别,前者常数稍大些

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<ctype.h>
     5 using namespace std;
     6 const int maxn=100100;
     7 int f[maxn][3],h[maxn];
     8 int read(){
     9     int x=0;
    10     char ch=getchar();
    11     while (!isdigit(ch)) ch=getchar();
    12     while (isdigit(ch)){
    13         x=x*10+ch-'0';
    14         ch=getchar();
    15     }
    16     return x;
    17 }
    18 int main(){
    19     int n=read();
    20     for (int i=1;i<=n;i++){
    21         h[i]=read();
    22         f[i][1]=f[i][2]=1;
    23     }
    24     int ans=1;
    25     for (int i=1;i<=n;i++){
    26         for (int j=i-1;j>0;j--){
    27             if (h[i]>h[j]) f[i][1]=max(f[i][1],f[j][2]+1);
    28             if (h[i]<h[j]) f[i][2]=max(f[i][2],f[j][1]+1);
    29             if (f[i][1]!=1&&f[i][2]!=1) break;
    30         }
    31     }
    32     printf("%d
    ",max(f[n][1],f[n][2]));
    33     return 0;
    34 }
    View Code
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<ctype.h>
     5 using namespace std;
     6 const int maxn=100100;
     7 int f[maxn][3],h[maxn];
     8 int read(){
     9     int x=0;
    10     char ch=getchar();
    11     while (!isdigit(ch)) ch=getchar();
    12     while (isdigit(ch)){
    13         x=x*10+ch-'0';
    14         ch=getchar();
    15     }
    16     return x;
    17 }
    18 int main(){
    19     int n=read();
    20     for (int i=1;i<=n;i++){
    21         h[i]=read();
    22         f[i][1]=f[i][2]=1;
    23     }
    24     for (int i=2;i<=n;i++){
    25         if (h[i]==h[i-1]) {
    26             f[i][1]=f[i-1][1];
    27             f[i][2]=f[i-1][2];
    28         }
    29         if (h[i]>h[i-1]){
    30             f[i][1]=max(f[i-1][2]+1,f[i][1]);
    31             f[i][2]=f[i-1][2];
    32         }
    33         if (h[i]<h[i-1]){
    34             f[i][1]=f[i-1][1];
    35             f[i][2]=max(f[i-1][1]+1,f[i][2]);
    36         }
    37     }
    38     printf("%d
    ",max(f[n][1],f[n][2]));
    39     return 0;
    40 }
    View Code

    还有一种更简洁的方法:对于一个单调序列中的所有点,可以缩为一个点,故只需统计原序列的拐点个数即可,也是O(n)

     

  • 相关阅读:
    创建你的 /proc 文件
    在 /proc 里实现文件
    使用 /proc 文件系统
    printk函数速率限制
    printk函数打开和关闭消息
    printk 函数消息是如何记录的
    mysql存储程序
    Javascript 笔记与总结(1-1)作用域
    Java实现 LeetCode 142 环形链表 II(二)
    Java实现 LeetCode 142 环形链表 II(二)
  • 原文地址:https://www.cnblogs.com/vincent-hwh/p/7352371.html
Copyright © 2011-2022 走看看