题解 [ABC339E] Smooth Subsequence

简单的 E,使我先跳过 D。

题意

给一个 N 个数的序列 A,你需要找到一个子序列满足相邻两个数之差的绝对值不超过 D,求子序列可能的最大长度。

分析

考虑动态规划。

状态设计

fi 表示以第 i 个数结尾最长的子序列长度。

转移方程

fi=1+maxj<i|AiAj|Dfj

观察到这是一个 O(n2) 的转移,时间复杂度不可接受,考虑优化。

1Ai5×105,并且转移方程中取最大值,可以用线段树优化。

时间复杂度 O(nlogAi),可以通过此题。

代码

//the code is from chenjh
#include<cstdio>
#include<algorithm>
#define MAXN 500005
#define lson (rt<<1)
#define rson (rt<<1|1)
using namespace std;
using ci=const int;
const int A=500000;//A 的最大值。
int n,d;
int mx[MAXN<<2];//线段树维护最大值
void update(ci rt,ci l,ci r,ci pos,ci val){
    if(l==r && l==pos){mx[rt]=max(mx[rt],val);return;}
    int mid=(l+r)>>1;
    if(pos<=mid) update(lson,l,mid,pos,val);
    else update(rson,mid+1,r,pos,val);
    mx[rt]=max(mx[lson],mx[rson]);
}
int query(ci rt,ci l,ci r,ci L,ci R){
    if(L<=l && r<=R) return mx[rt];
    int mid=(l+r)>>1,ret=0;
    if(L<=mid) ret=max(ret,query(lson,l,mid,L,R));
    if(mid<R) ret=max(ret,query(rson,mid+1,r,L,R));
    return ret;
}
int main(){
    scanf("%d%d",&n,&d);
    for(int i=1,a;i<=n;i++)
        scanf("%d",&a),update(1,1,A,a,query(1,1,A,max(a-d,1),min(a+d,A))+1);//求出 f_i 更新最大值。
    printf("%d\n",query(1,1,A,1,A));//查询整个动态规划数组的最大值。
    return 0;
}
posted @   Chen_Jinhui  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端

一言

梦是现实的延续,现实是梦的终结。
——Eva
点击右上角即可分享
微信分享提示