hdu 4521 小明序列(线段树,DP思想)

题意:

①首先定义S为一个有序序列,S={ A1 , A2 , A3 , ... , An },n为元素个数 ;
  ②然后定义Sub为S中取出的一个子序列,Sub={ Ai1 , Ai2 , Ai3 , ... , Aim },m为元素个数 ;
  ③其中Sub满足 Ai1 < Ai2 < Ai3 < ... < Aij-1 < Aij < Aij+1 < ... < Aim ;
  ④同时Sub满足对于任意相连的两个Aij-1与Aij都有 ij - ij-1 > d (1 < j <= m, d为给定的整数);
  ⑤显然满足这样的Sub子序列会有许许多多,而在取出的这些子序列Sub中,元素个数最多的称为“小明序列”(即m最大的一个Sub子序列)。
  例如:序列S={2,1,3,4} ,其中d=1;
  可得“小明序列”的m=2。即Sub={2,3}或者{2,4}或者{1,4}都是“小明序列”。

  当小明发明了“小明序列”那一刻,情绪非常激动,以至于头脑凌乱,于是他想请你来帮他算算在给定的S序列以及整数d的情况下,“小明序列”中的元素需要多少个呢?

思路:

DP的思想,但是只能想到N^2的算法。嘿嘿正好题目有说(0<=Ai<=10^5),那就是了,用线段树保存最值。

每次做题都要考虑周全,边界什么的,,

d=0时单独用贪心的方法算,其实不用也可以,。

代码:

int const N = 100005;

int a[N], f[N];
int F[N<<2];
int n,d;

void PushUp(int rt){
    F[rt]=max( F[rt<<1],F[rt<<1|1] );
    return;
}

void build(int l,int r,int rt){
    if(l==r){
        F[rt]=0;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}

void update(int pos,int x,int l,int r,int rt){
    if(l==r){
        F[rt]=max( F[rt],x );
        return;
    }
    int m=(l+r)>>1;
    if(pos<=m)
        update(pos,x,lson);
    else
        update(pos,x,rson);
    PushUp(rt);
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l && r<=R){
        return F[rt];
    }
    int m=(l+r)>>1;
    int res=0;
    if(L<=m)
        res=max( res,query(L,R,lson) );
    if(m<R)
        res=max( res,query(L,R,rson) );
    return res;
}

int proc1(){
    int d[N];
    int cn=0;
    d[0]=-1;

    rep(i,1,n){
        if(a[i]>d[cn]){
            d[++cn]=a[i];
        }else{
            int pos=lower_bound(d+1,d+1+cn,a[i])-d;
            d[pos]=a[i];
        }
    }
    return cn;
}

int main(){

    while(scanf("%d%d",&n,&d)!=EOF){

        int es=-inf;

        rep(i,1,n){
            scanf("%d",&a[i]);
            es=max( es,a[i] );
        }

        if(d==0){
            int ans=proc1();
            printf("%d\n",ans);
        }else{
            build(0,es,1);
            int ans=1;

            rep(i,1,n){
                if(i-d-1<=0){
                    f[i]=1;
                }else{
                    update(a[i-d-1],f[i-d-1],0,es,1); //pos,x,l,r,rt
                    if(a[i]==0){
                        f[i]=1;
                        continue;
                    }
                    int t=query(0,a[i]-1,0,es,1); //L,R,l,r,rt
                    f[i]=t+1;
                    ans=max( ans,f[i] );
                }
            }
            printf("%d\n",ans);
        }
    }

    return 0;
}
时间: 2024-10-17 16:49:54

hdu 4521 小明序列(线段树,DP思想)的相关文章

hdu 4521 小明系列问题——小明序列(线段树+DP或扩展成经典的LIS)

小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1553    Accepted Submission(s): 457 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,但是也就由于这样,小明差点儿已经玩遍各种序列问题了.可怜的小明苦苦地在各大站点上寻找着新的序列问题,但是找来

hdu 4521 小明系列问题——小明序列 线段树+二分

小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找去都是自己早已研究过的序列.小明想既然找不到,那就自己来发明一个新的序列问题吧!小明想啊想,终于想出了一个新的序列

hdu45221——小明系列问题——小明序列 线段树优化dp

小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1918    Accepted Submission(s): 583 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找

HDU 4521 小明系列问题——小明序列 (线段树维护DP)

题目地址:HDU 4521 基本思路是DP.找前面数的最大值时能够用线段树来维护节省时间. 因为间隔要大于d. 所以能够用一个队列来延迟更新,来保证每次询问到的都是d个之前的. 代码例如以下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include

hdu 4521 小明系列问题——小明序列 (间隔至少为d的LIS 两种解法)

先附上资源地址:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html 进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握. 最近,我读到一篇材料,发现有一个很好的类比,可以把它们解释地清晰易懂. 1. 计算机的核心是CPU,它承担了所有的计算任务.它就像一座工厂,时刻在运行. 2. 假定工厂的电力有限,一次只能供给一个车间使用.也就是说,一个车间开工的时候,其他车间都必须停工

HDU 4521 小明系列问题——小明序列 (LIS加强版)

小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1946    Accepted Submission(s): 596 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题, 可是找来找

HDU - 4521 小明系列问题――小明序列 (存在间隔的LIS)

Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找去都是自己早已研究过的序列.小明想既然找不到,那就自己来发明一个新的序列问题吧!小明想啊想,终于想出了一个新的序列问题,他欣喜若狂,因为是自己想出来的,于是将其新序列问题命名为"小明序列". 提起小明序列,他给出的定义是这样的: ①首先定义S为一个有序序列,S={ A1 , A2 , A3 , ... , An

hdu 4521 小明系列问题——小明序列 (LIS变形)

小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1848    Accepted Submission(s): 564 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找

hdu 4521 小明系列问题——小明序列(线段树 or DP)

题目链接:hdu 4521 本是 dp 的变形,却能用线段树,感觉好强大. 由于 n 有 10^5,用普通的 dp,算法时间复杂度为 O(n2),肯定会超时.所以用线段树进行优化.线段树维护的是区间内包含某点的最大满足条件的长度,叶子节点以该元素结尾,最长长度.至于相邻两项隔 d 个位置,求 dp[i] 时,我们只把 dp[i - d - 1] 更新至线段树中,然后在这颗线段树中找最大的个数. 具体来说,就是把序列 S 的值 Ai 作为线段树叶子下标,以 Ai 结尾的 LIS 长度(即经典算法里