题解 [ABC339E] Smooth Subsequence

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

题意

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

分析

考虑动态规划。

状态设计

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

转移方程

$$ f_i = 1 + \max\limits_{j<i \land \vert A_i - A_j \vert \le D} f_j $$

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

$1 \le A_i \le 5 \times 10^5$,并且转移方程中取最大值,可以用线段树优化。

时间复杂度 $O(n \log A_i)$,可以通过此题。

代码

//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 @ 2024-02-04 08:34  Chen_Jinhui  阅读(20)  评论(0)    收藏  举报  来源