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\n",ans);
74     }
75     return 0;
76 }

时间: 2024-10-29 19:09:39

hdu 4521 小明系列问题——小明序列(线段树 or DP)的相关文章

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 小明系列问题——小明序列 线段树+二分

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

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 小明系列问题——小明序列(线段树+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 小明系列问题——小明序列 (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 5421 小明系列问题——小明序列(LIS最长上升子序列)

1 /***************************************************** 2 题目: 小明系列问题——小明序列(hdu 4521) 3 链接: http://acm.hdu.edu.cn/showproblem.php?pid=4521 4 算法: LIS最长上升子序列 5 6 ******************************************************/ 7 #include<cstdio> 8 #include<

HDOJ 题目4521 小明系列问题——小明序列(LIC增强版)

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

小明系列问题――小明序列(LIS)

小明系列问题――小明序列 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4521 Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找去都是自己早已研究过的序列.小明想既然找不到,那就自己来发明一个新的序列问题吧!