题解 [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;
}

浙公网安备 33010602011771号