HDU 4521 2013腾讯编程马拉松初赛第四场 小明系列问题——小明序列(dp思想+线段树优化)

来源:互联网 发布:数控铣床编程实例带图 编辑:程序博客网 时间:2024/05/29 04:59

这个题的话,最开始想的是普通dp,但是看了一下数据规模10的5次方,O(N*N)肯定是会超时的,那么就想了一下,用线段树优化dp的查询过程

首先用线段树维护的是以当前点为序列最后一个点所能够达到的最大长度,为了避免影响到当前点的判断,所以在判断下一个点之前才更新当前这个点,具体的操作看代码

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>using namespace std;#define lc l,m,index<<1#define rc m+1,r,index<<1|1int num[100005],dp[100005];int cnt[100005<<2];int n,m;int MAX(int a,int b){    return a>b?a:b;}void updata(int l,int r,int index,int id,int mx)  //更新当前点的前一个点{    cnt[index]=MAX(cnt[index],mx);    if(l==r)    return;    int m=(r+l)>>1;    if(id<=m)    updata(lc,id,mx);    else    updata(rc,id,mx);return;}void build(int l,int r,int index){    cnt[index]=0;    if(l==r)    return ;    int m=(l+r)>>1;    build(lc);    build(rc);return ;}int query(int L,int R,int l,int r,int index) //查找区间最大值{   if(L<=l && R>=r)      return cnt[index];   int m=(l+r)>>1;   int Max=0;   if(L<=m)      Max=MAX(Max,query(L,R,lc));   if(R>m)      Max=MAX(Max,query(L,R,rc));   return Max;}int main(){    while(~scanf("%d%d",&n,&m))    {       memset(dp,0,sizeof(dp));        int MX=0;        for(int i=1;i<=n;i++)        {            scanf("%d",&num[i]);            MX=MAX(MX,num[i]);        }        build(0,MX,1);        int mx=0;        for(i=1;i<=n;i++)        {            if(i-m-1>=1)             //根据题意要在i-m-1开始对线段树进行更新            updata(0,MX,1,num[i-m-1],dp[i-m-1]);if(num[i]==0) //如果当前点为0,那么前一个点就是-1,所以特判0dp[i]=1;else            dp[i]=1+query(0,num[i]-1,0,MX,1); //询问0到当前点num[i]的前一个点num[i]-1,最大长度为多少            mx=MAX(mx,dp[i]);        }        printf("%d\n",mx);    }  // system("pause");    return 0;}


原创粉丝点击