zoukankan      html  css  js  c++  java
  • hdu4521 小明序列 (线段树 + DP)

    题意:题目的意思很简单,给定一个序列,求最大递增子序列的长度,同时相邻俩项下标的差值必须大于d

    分析:就题意而已,只是在最长递增子序列的加了一个限制条件,沿用最长递增子序列的思路,则dp[i] = max(dp[i], dp[j] + 1), (i - j > d && a[i] > a[j])

    从状态转移方程可以看出,问题的关键在于维护区间(0,i - d - 1)  最大的dp值,且对应值小于a[i]

    我们换一种角度,用a[i]的值作为下标,保证当前区间(0, a[i] - 1) 中的dp值都满足 (i - j > d) , 那么dp[i] 就等于区间(0, a[i] - 1) 的最大值, 这个就可以用线段树来解决了

    hdu4521
    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    
    using namespace std;
    
    const int N = 100000 + 10;
    
    struct node
    {
        int l, r, max;
    }p[N * 3];
    
    int a[N], d, n;
    int dp[N];
    
    void build(int s, int t, int k)
    {
        p[k].l = s;
        p[k].r = t;
        p[k].max = 0;
        if( s == t ) return ;
        int mid = (s + t) >> 1, kl = k << 1, kr = kl + 1;
        build(s, mid, kl);
        build(mid + 1, t, kr);
    }
    
    void insert(int k, int s, int val)
    {
        if( p[k].l == p[k].r && p[k].l == s)
        {
            p[k].max = max(p[k].max, val);
            return ;
        }
        int mid = (p[k].l + p[k].r) >> 1, kl = k << 1, kr = kl + 1;
        if( s <= mid) insert(kl, s, val);
        else insert(kr, s, val);
        p[k].max = max(p[kl].max, p[kr].max); 
    }
    
    int query(int k, int s, int t)
    {
        if(s <= p[k].l && t >= p[k].r)
        {
            return p[k].max;
        }
    
        int mid = (p[k].l + p[k].r) >> 1, kl = k << 1, kr = kl + 1;
        int a = 0, b = 0;
        if(s <= mid) a = query(kl, s, t);
        if(t > mid) b = query(kr, s, t);
        return max(a, b);
    }
    
    int main()
    {
        while(scanf("%d %d", &n, &d) == 2)
        {
            int maxa = 0;
            for(int i = 1; i <= n; ++i)
            {
                scanf("%d", a + i);
                ++a[i];
                maxa = max(maxa, a[i]);
            }
            memset(dp, 0, sizeof(dp));
            build(0, maxa, 1);
            int ans = 1;
            for(int i = 1; i <= n; ++i)
            {
                int tmp = query(1, 0, a[i] - 1);
                dp[i] = max(dp[i], tmp + 1);
                ans = max(ans, dp[i]);
                if(i - d > 0) insert(1, a[i - d], dp[i - d]);//在线段树中插入满足下标满足的DP值
            }
            printf("%d\n",ans);
        }
        return 0;
    }
  • 相关阅读:
    零基础学习java------day1------计算机基础以及java的一些简单了解
    Mongodb的简单使用
    02-爬取http://www.allitebooks.org/网站,获取图片url,书名,简介,作者
    商业爬虫学习笔记day8-------json的使用
    商业爬虫学习笔记day7-------解析方法之bs4
    商业爬虫学习笔记day6
    练习1--爬取btc论坛的title和相应的url
    商业爬虫学习笔记day5
    cookie规范(RFC6265)翻译
    [POJ] 1511 Invitation Cards
  • 原文地址:https://www.cnblogs.com/nanke/p/2994358.html
Copyright © 2011-2022 走看看