zoukankan      html  css  js  c++  java
  • hdu 4521 小明系列问题——小明序列(线段树 or DP)

      题目链接:hdu 4521

      本是 dp 的变形,却能用线段树,感觉好强大。

      由于 n 有 10^5,用普通的 dp,算法时间复杂度为 O(n2),肯定会超时。所以用线段树进行优化。线段树维护的是区间内包含某点的最大满足条件的长度,叶子节点以该元素结尾,最长长度。至于相邻两项隔 d 个位置,求 dp[i] 时,我们只把 dp[i - d - 1] 更新至线段树中,然后在这颗线段树中找最大的个数。

      具体来说,就是把序列 S 的值 Ai 作为线段树叶子下标,以 Ai 结尾的 LIS 长度(即经典算法里的 dp[i])作为叶子结点的值,然后对每个 Ai,查询 0 ~ Ai - 1 的最大的 LIS 长度(也就是 dp[]),这个用线段树实现可以很快地得到结果;至于更新时,不能每遍历到一个就直接更新,因为这样子的话 A[i - d] ~ A[i - 1] 会被加入到线段树中,它们对 A[i] 无任何作用,却会对线段树的查询结果有干扰,因此我们在对每一个 Ai 进行查询(即计算出对应的 dp[i])前,就只把 A[i - d - 1] 即 dp[i - d - 1] 加入到线段树中即可,这个操作是很关键的。理清思路后,就是线段树的单点更新、区间查询了。

      因为我写线段树习惯从 1 开始,所以对所有元素都 +1 了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 #define  root  int rt, int l, int r
     6 #define  lson  rt << 1, l, mid
     7 #define  rson  rt << 1 | 1, mid + 1, r
     8 #define  makemid  int mid = l + r >> 1
     9 const int N = 100005;
    10 
    11 int len[N << 2];
    12 
    13 void build(root) {
    14     len[rt] = 0;
    15     if(l == r)  return ;
    16     makemid;
    17     build(lson);
    18     build(rson);
    19 }
    20 
    21 inline void pushup(int rt) {
    22     len[rt] = max(len[rt << 1], len[rt << 1 | 1]);
    23 }
    24 
    25 int pos, val;
    26 void update(root) {
    27     if(l == r) {
    28         len[rt] = max(len[rt], val);
    29         return ;
    30     }
    31     makemid;
    32     if(pos <= mid)  update(lson);
    33     else    update(rson);
    34     pushup(rt);
    35 }
    36 
    37 int ql,qr;
    38 int query(root) {
    39     if(ql <= l && r <= qr)  return len[rt];
    40     makemid;
    41     int res = 0;
    42     if(ql <= mid)   res = max(res, query(lson));
    43     if(qr > mid)    res = max(res, query(rson));
    44     return res;
    45 }
    46 
    47 int dp[N], num[N];
    48 
    49 int main() {
    50     int n,d;
    51     while(~scanf("%d%d",&n,&d)) {
    52         int mm = 0, ans = 0;
    53         for(int i = 1; i <= n; ++i) {
    54             scanf("%d",num + i);
    55             ++num[i];
    56             mm = max(mm, num[i]);
    57         }
    58         build(1,1,mm);
    59         for(int i = 1; i <= n; ++i) {
    60             if(i - d - 1 >= 1) {        //这是关键,只把 i-d-1 前面的更新至线段树中
    61                 pos = num[i - d - 1];
    62                 val = dp[i - d - 1];
    63                 update(1,1,mm);
    64             }
    65             if(num[i] == 1)    dp[i] = 1;
    66             else {
    67                 ql = 1;
    68                 qr = num[i] - 1;
    69                 dp[i] = query(1,1,mm) + 1;
    70             }
    71             ans = max(ans, dp[i]);
    72         }
    73         printf("%d
    ",ans);
    74     }
    75     return 0;
    76 }
    View Code
  • 相关阅读:
    spring源码-BeanFactoryPostProcessor-3.2
    web之前端获取上传图片并展示
    spring源码-增强容器xml解析-3.1
    spring源码-bean之增强初始化-3
    spring源码-bean之加载-2
    spring源码-bean之初始化-1
    spring源码-开篇
    java之扫描包里面的class文件
    vuex状态持久化
    Vue 使用 vuelidate 实现表单验证
  • 原文地址:https://www.cnblogs.com/Newdawn/p/4859766.html
Copyright © 2011-2022 走看看