• [NOIP2013] 花匠


    初看这道题想到O(n2) 的暴力dp

    用f[i][0]表示取第i个点为最低点时的答案, f[i][1]为最高点,且f[i][0] = max( f[j][1] ) +1

    这样每次都要查询前面区间满足 h[i]>h[j] 的最大值, 可以考虑 线段树区间查询 或者 BIT 或者BST , 时间降至O(nlogn)

    但是BIT时要注意查询h[i]<h[j] 条件时涉及到 j ~ maxheight 的最值查询, 可以把maxheight -h[i] +2 (BIT下标不为0) 存入树状数组

    RE 代码:BIT 误取最大下标为n!! 实际上应该在读入时求出maxheight!!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #include<string>
    #include<iomanip>
    #include<ctime>
    #include<climits>
    #include<cctype>
    #include<algorithm>
    #ifdef WIN32
    #define AUTO "%I64d"
    #else
    #define AUTO "%lld"
    #endif
    using namespace std;
    #define lowbit(x) x&-x
    #define smax(x,tmp) x=max(x,tmp)
    const int maxn=100005;
    const int INF=0x3f3f3f3f;
    int high[maxn],low[maxn];//!! LAST RE!!! BIT  must be bigger!! maxheight!!!
    int f[maxn][2];//0: low point ; 1: high point
    int a[maxn];
    int n;
    int maxheight=-INF;
    inline void add_low(int x,int val)
    {
        for(int i=x;i<=maxheight+1;i+=lowbit(i)) smax(low[i],val);//also easy to consider as n!!
    }
    inline void add_high(int x,int val)
    {
        for(int i=x;i<=maxheight+1;i+=lowbit(i)) smax(high[i],val);    
    }
    inline int query_low(int x)
    {
        int ret=0;
        for(int i=x;i;i-=lowbit(i))    smax(ret,low[i]);
        return ret;
    }
    inline int query_high(int x)
    {
        int ret=0;
        for(int i=x;i;i-=lowbit(i)) smax(ret,high[i]);
        return ret;
    }
    
    int main()
    {
        freopen("flower.in","r",stdin);
        freopen("flower.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i),smax(maxheight,a[i]);
        int ans=1;
        f[1][0]=f[1][1]=1;
        add_low(a[1]+1,f[1][0]);add_high(maxheight-a[1]+2,f[1][1]);//add reversely, to query the max !!
        for(int i=2;i<=n;i++)
        {
            f[i][0]=query_high(maxheight-a[i]+1)+1;
            f[i][1]=query_low(a[i])+1;
            add_low(a[i]+1,f[i][0]);//can't either!!
            add_high(maxheight-a[i]+2,f[i][1]);// mustn't use the 0 point !!
            smax(ans,max(f[i][0],f[i][1]));
        }
        printf("%d",ans);
        return 0;
    }
    View Code

    AC代码:(BIT)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #include<string>
    #include<iomanip>
    #include<ctime>
    #include<climits>
    #include<cctype>
    #include<algorithm>
    #ifdef WIN32
    #define AUTO "%I64d"
    #else
    #define AUTO "%lld"
    #endif
    using namespace std;
    #define lowbit(x) x&-x
    #define smax(x,tmp) x=max(x,tmp)
    const int maxn=100005;
    const int maxh=1000005;
    const int INF=0x3f3f3f3f;
    int high[maxh],low[maxh];//for BIT
    int f[maxn][2];//0: low point ; 1: high point
    int a[maxn];
    int n;
    int maxheight=-INF;
    inline void add_low(int x,int val)
    {
        for(int i=x;i<=maxheight+1;i+=lowbit(i)) smax(low[i],val);
    }
    inline void add_high(int x,int val)
    {
        for(int i=x;i<=maxheight+1;i+=lowbit(i)) smax(high[i],val);    
    }
    inline int query_low(int x)
    {
        int ret=0;
        for(int i=x;i;i-=lowbit(i))    smax(ret,low[i]);
        return ret;
    }
    inline int query_high(int x)
    {
        int ret=0;
        for(int i=x;i;i-=lowbit(i)) smax(ret,high[i]);
        return ret;
    }
    
    int main()
    {
        freopen("flower.in","r",stdin);
        freopen("flower.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i),smax(maxheight,a[i]);
        int ans=1;
        f[1][0]=f[1][1]=1;
        add_low(a[1]+1,f[1][0]);add_high(maxheight-a[1]+2,f[1][1]);//add reversely, to query the max !!
        for(int i=2;i<=n;i++)
        {
            f[i][0]=query_high(maxheight-a[i]+1)+1;
            f[i][1]=query_low(a[i])+1;
            add_low(a[i]+1,f[i][0]);//can't either!!
            add_high(maxheight-a[i]+2,f[i][1]);// mustn't use the 0 point !!
            smax(ans,max(f[i][0],f[i][1]));
        }
        printf("%d",ans);
        return 0;
    }
    
    
    //O(n): f[i][0,1] indicates that don't need to stop at i, but had the previous cases
    
    //O(n): find the corners with the tendency
    View Code

    现虑另一种 O(n) 的dp

    用f[i][0,1] 表示 i 及其以前所有高度的最大值,但是0 表示之前出于下降阶段而并非之前的上一个节点为转折点, 仅仅表示一个趋势

    另一种 o(n) 算法

    由于一段相同变化趋势的区段内只能留下一个端点

    故只需要统计出所有的”拐点“即可!

    WA代码: 只考虑到相邻的几个数,但是缺乏长远的考虑!!!!应用趋势来判断!!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #include<string>
    #include<iomanip>
    #include<ctime>
    #include<climits>
    #include<cctype>
    #include<algorithm>
    #ifdef WIN32
    #define AUTO "%I64d"
    #else
    #define AUTO "%lld"
    #endif
    using namespace std;
    #define lowbit(x) x&-x
    #define smax(x,tmp) x=max(x,tmp)
    const int maxn=100005;
    const int INF=0x3f3f3f3f;
    int n;
    int a[maxn];
    int main()
    {
        freopen("flower.in","r",stdin);
        freopen("flower.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        int ans=2;
        for(int i=2;i^n;i++)
        {
            if(a[i-1]>a[i] && a[i]<a[i+1]) ans++;//Last WA!! not only the near one, but long trems
            if(a[i-1]<a[i] && a[i]>a[i+1]) ans++;
        }
        printf("%d",ans);
        return 0;
    }
    View Code

    AC代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #include<string>
    #include<iomanip>
    #include<ctime>
    #include<climits>
    #include<cctype>
    #include<algorithm>
    #ifdef WIN32
    #define AUTO "%I64d"
    #else
    #define AUTO "%lld"
    #endif
    using namespace std;
    #define lowbit(x) x&-x
    #define smax(x,tmp) x=max(x,tmp)
    const int maxn=100005;
    const int INF=0x3f3f3f3f;
    int n;
    int a[maxn];
    int main()
    {
        freopen("flower.in","r",stdin);
        freopen("flower.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        int ans=1;//indicates the first one to start!!
        int flag=0;//indicates start!!
        for(int i=1;i^n;i++)
        {
            if(a[i]<a[i+1] && (flag==0 || flag==-1)) flag=1,ans++;
            if(a[i]>a[i+1] && (flag==0 || flag==1)) flag=-1,ans++;
        }
        printf("%d",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    SOD开源框架MSF(消息服务框架)介绍
    c#中foreach的一种用法
    MSSql异常处理框架
    什么是架构?有几人说的清楚
    MSSql动态行转列
    WebForm版demo,模拟手机Usb接口充电
    规范化流程不能窥探的咪咪
    我对领导者的定义
    以乞丐为最大的贵客
    程序猿,是如何逆袭的
  • 原文地址:https://www.cnblogs.com/ourfutr2330/p/5665054.html
Copyright © 2020-2023  润新知