题目描述
Marmot found a row with n n n pillars. The i i i -th pillar has the height of h i h_{i} hi meters. Starting from one pillar i 1 i_{1} i1 , Marmot wants to jump on the pillars i 2 i_{2} i2 , …, i k i_{k} ik . ( 1 < = i 1 < i 2 < . . . < i k < = n 1<=i_{1}<i_{2}<...<i_{k}<=n 1<=i1<i2<...<ik<=n). From a pillar i i i Marmot can jump on a pillar j j j only if i < j i<j i<j and ∣ h i − h j ∣ > = d |h_{i}-h_{j}|>=d ∣hi−hj∣>=d , where ∣ x ∣ |x| ∣x∣ is the absolute value of the number x x x.
Now Marmot is asking you find out a jump sequence with maximal length and print it.
输入格式
The first line contains two integers n and d (1 ≤ n ≤ 10^5, 0 ≤ d ≤ 10^9).
The second line contains n numbers h1, h2, …, hn (1 ≤ hi ≤ 10^15).
输出格式
The first line should contain one integer k, the maximal length of a jump sequence.
The second line should contain k integers i1, i2, …, ik (1 ≤ i1 < i2 < … < ik ≤ n), representing the pillars’ indices from the maximal length jump sequence.
If there is more than one maximal length jump sequence, print any.
Sample Input 1
5 2
1 3 6 7 4
Sample Output 1
4
1 2 3 5
Sample Input 2
10 3
2 1 3 6 9 11 7 3 20 18
Sample Output 2
6
1 4 6 7 8 9
提示
In the first example Marmot chooses the pillars 1 1 1 , 2 2 2 , 3 3 3 , 5 5 5 with the heights 1 1 1 , 3 3 3 , 6 6 6 , 4 4 4 . Another jump sequence of length 4 4 4 is 1 1 1 , 2 2 2 , 4 4 4 , 5 5 5 .
1 ≤ n ≤ 1 0 5 , 0 ≤ d ≤ 1 0 9 , 1 ≤ a i ≤ 1 0 15 1\leq n\leq 10^5,0\leq d\leq 10^9,1\leq a_i\leq 10^{15} 1≤n≤105,0≤d≤109,1≤ai≤1015
题目大意
给出一个长度为 n n n的序列 h h h和一个整数 d d d。要求找出一个子序列,使得
- ∣ h i + 1 − h i ∣ ≥ d |h_{i+1}-h_i|\geq d ∣hi+1−hi∣≥d
- h h h的长度最大
求序列长度和这个序列。
题解
前置知识:线段树优化DP
首先将 a i a_i ai离散化,然后用线段树维护。
设 f i f_i fi表示前 i i i个数所能组成的最长的序列的长度。对于每个 h i h_i hi,在线段树上查询 [ 1 , h i − d ] [1,h_i-d] [1,hi−d]和 [ h i + d , m x h ] [h_i+d,mxh] [hi+d,mxh],其中 m x h mxh mxh是 h h h数组的最大值。
在转移的时候顺便记录一下是从哪个点转移过来的,即可输出序列。总时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
code
#include<algorithm>
#include<iostream>
#include<cstdio>
#define lc k<<1
#define rc k<<1|1
using namespace std;
int n,d,sum,lst,k[100005],f[100005],p[100005],tr[400005],gt[400005],ans[100005];
long long a[100005],num[100005];
void ch(int k,int l,int r,int x,int y,int fr){
if(l==r&&l==x){
if(y>tr[k]){
tr[k]=y;gt[k]=fr;
}
return;
}
if(l>x||r<x) return;
if(l==r) return;
int mid=(l+r)/2;
if(x<=mid) ch(lc,l,mid,x,y,fr);
else ch(rc,mid+1,r,x,y,fr);
if(tr[lc]>tr[rc]){
tr[k]=tr[lc];gt[k]=gt[lc];
}
else{
tr[k]=tr[rc];gt[k]=gt[rc];
}
}
void find(int k,int l,int r,int x,int y){
if(l>=x&&r<=y){
if(tr[k]>sum){
sum=tr[k];lst=gt[k];
}
return;
}
if(l>y||r<x) return;
if(l==r) return;
int mid=(l+r)/2;
if(x<=mid) find(lc,l,mid,x,y);
if(y>mid) find(rc,mid+1,r,x,y);
}
int main()
{
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
num[i]=a[i];
}
sort(num+1,num+n+1);
int gs=unique(num+1,num+n+1)-num-1;
num[++gs]=1e18;
for(int i=1;i<=n;i++){
k[i]=lower_bound(num+1,num+gs+1,a[i])-num;
}
for(int i=1;i<=n;i++){
sum=0;lst=0;
int v=upper_bound(num+1,num+gs+1,a[i]-d)-num-1;
if(v>=1) find(1,1,gs,1,v);
v=lower_bound(num+1,num+gs+1,a[i]+d)-num;
find(1,1,gs,v,gs);
f[i]=sum+1;p[i]=lst;
ch(1,1,gs,k[i],f[i],i);
}
printf("%d\n",tr[1]);
for(int i=gt[1];i;i=p[i])
ans[++ans[0]]=i;
for(int i=ans[0];i>=1;i--)
printf("%d ",ans[i]);
return 0;
}