• [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)

     

  • 相关阅读:
    软链接mongo
    添加系统路径
    安装mongodb扩展
    查看php扩展
    查看mongodb状态
    phpExcel 替代 产品, 可导出10W数据,无压力
    饭饭之辈 200 Vue2.0生命周期(组件钩子函数与路由守卫)
    vue 父组件监听子组件事件,emit携带参数,且父组件也自带参数问题
    xlswriter 使用文档,快速写入xls 支持 2007以上的版本
    vue 中组件传值问题
  • 原文地址:https://www.cnblogs.com/vincent-hwh/p/7352371.html
Copyright © 2020-2023  润新知