1. 程式人生 > >HDU - 4521 小明系列問題——小明序列 (dp + 線段樹)

HDU - 4521 小明系列問題——小明序列 (dp + 線段樹)

題意
還是LIS,不過有一個限制條件是選擇的節點必須相差d。
思路
d p 方程其實還是

" role="presentation" style="position: relative;"> dp[i] = max(dp[j]) + 1 (0 < j < i && a[i] > a[j])
只不過是 j i 又加了一個條件
j + d > i
而已,那麼具體怎麼寫?很簡單我們用線段樹去維護 m a x ( d p [ j ] ) ,具體怎麼維護?我們把所有的點離散,之後以離散過後的點建立線段樹,之後對於每次遇到第 i 個點,我們把第 i d 1 這個點放進線段樹裡面,然後我們查詢(1,p-1]這個位置的最大值,那麼我們就可以完美的解決距離問題和 a [ i ] > a [ j ] 這個問題了。
(ps) 這題不離散竟然比離散還有快。。。是我寫搓了?
程式碼

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 1e5+10;
int  tree[maxn<<2] , dp[maxn] , a[maxn],Hash[maxn] , cnt;
void pushup(int rt)
{
    tree[rt] = max(tree[rt<<1] , tree[rt<<1|1]);
}

void update(int pos,int val,int l,int r,int rt)
{
    if(l == r)
    {
        tree[rt] = max(tree[rt] , val);
        return ;
    }
    int m = (l+r)>>1;
    if(m>=pos) update(pos,val,lson);
    else update(pos,val,rson);
    pushup(rt);
}

int query(int L,int R,int l,int r,int rt)
{ 
    if(L>R) return 0;
    if(L<=l && r<=R) return tree[rt];
    int m = (l+r)>>1;
    int ret = 0;
    if(L<=m) ret = max(ret,query(L,R,lson));
    if(R>m) ret = max(ret,query(L,R,rson));
    return ret;
}

int main()
{
    int n,d;
    while(scanf("%d%d",&n,&d)!=EOF)
    {
        memset(tree,0,sizeof(tree));
        cnt = 0;
        for(int i = 1 ; i <= n ; i++)
        {
            scanf("%d",&a[i]);
            Hash[cnt++] = a[i];
        }
        sort(Hash,Hash+cnt);
        cnt = unique(Hash,Hash+cnt) - Hash;
        for(int i = 1 ; i <= n ; i++) dp[i] = 1;
        int ans = 0;
        if(n < d + 2) {puts("1");continue;} // 沒有加這特判wa了一晚上
        for(int i = d + 2 ; i <= n ;i ++)
        {
            int p = lower_bound(Hash,Hash+cnt,a[i]) - Hash + 1; // 當前點所在的大小
            int p2 = lower_bound(Hash,Hash+cnt,a[i-d-1]) - Hash + 1; // 我們把第i-d-1這個數字放到線段樹裡,就可以完美的解決限制問題
            update(p2,dp[i-d-1],1,n,1);
            int te = query(1,p-1,1,n,1);  // 查詢(1,p-1]裡的最大值,
        //  cout<<te<<endl;
            dp[i] = te + 1;
            ans = max(ans,dp[i]);
        }
        printf("%d\n",ans);
    }
}