【HDU4521】 dp思想+线段树操作

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4521

题目大意:有n个数,求间距大于d的最长递增子序列。

 

解题思路:扎眼一看,不是简单的dp嘛,再眨眼一看,n最大为10^5,蛋碎一地呀。

              这题不仅要线段树功底好,还要有比较强的dp思想,从第d+1个位置开始更新,每个节点的sum值保存的是从第1个数到当前数的最长符合要求的子序列,查询的时候只需查询线段树中值在其左边的最大的sum[u](最长符合要求序列)。

 

 1 #include <iostream>

 2 #include <cstdio>

 3 #include <cstring>

 4 #include <queue>

 5 #include <algorithm>

 6 using namespace std;

 7 

 8 #define lz 2*u,l,mid

 9 #define rz 2*u+1,mid+1,r

10 const int maxn=110000;

11 int sum[2*maxn], dp[maxn+5], a[maxn+5];

12 

13 void Update(int u, int l, int r, int p, int c)

14 {

15     sum[u]=max(sum[u],c);

16     if(l==r)return ;

17     int mid=(l+r)>>1;

18     if(p<=mid) Update(lz,p,c);

19     else Update(rz,p,c);

20 }

21 

22 int Query(int u, int l, int r, int tl, int tr)

23 {

24     if(tl>tr) return 0;

25     if(tl<=l&&r<=tr) return sum[u];

26     int mid=(l+r)>>1;

27     if(tr<=mid) return Query(lz,tl,tr);

28     else if(tl>mid) return Query(rz,tl,tr);

29     else

30     {

31         int t1=Query(lz,tl,mid);

32         int t2=Query(rz,mid+1,tr);

33         return max(t1,t2);

34     }

35 }

36 

37 int main()

38 {

39     int n, d;

40     while(scanf("%d%d",&n,&d)!=EOF)

41     {

42         memset(sum,0,sizeof(sum));

43         for(int i=1; i<=n; i++)

44             scanf("%d",a+i);

45         int maxx=0;

46         for(int i=1; i<=n; i++)

47         {

48             if(i>d+1) Update(1,1,maxn,a[i-d-1]+1,dp[i-d-1]);  ///注意a[i-d-1]要加1

49             dp[i]=Query(1,1,maxn,1,a[i])+1;

50             maxx=max(dp[i],maxx);

51         }

52         printf("%d\n",maxx);

53     }

54     return 0;

55 }

 

你可能感兴趣的:(HDU)