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
  • 相关阅读:
    deeplearning.ai 卷积神经网络 Week 1 卷积神经网络
    deeplearning.ai 构建机器学习项目 Week 2 机器学习策略 II
    deeplearning.ai 构建机器学习项目 Week 1 机器学习策略 I
    deeplearning.ai 改善深层神经网络 week3 超参数调试、Batch Normalization和程序框架
    deeplearning.ai 改善深层神经网络 week2 优化算法
    deeplearning.ai 改善深层神经网络 week1 深度学习的实用层面
    cs231n spring 2017 lecture8 Deep Learning Networks
    cs231n spring 2017 lecture7 Training Neural Networks II
    cs231n spring 2017 lecture6 Training Neural Networks I
    cs231n spring 2017 Python/Numpy基础
  • 原文地址:https://www.cnblogs.com/Newdawn/p/4859766.html
Copyright © 2011-2022 走看看