[NOIP2013] 花匠

2018-06-18 00:00:19来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

初看这道题想到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

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:C++通过域名获取IP地址的方法;调试通过!

下一篇:NOIP2011(提高组)DAY2---观光公交(vijosP1741)