CF 474E Pillars(线段树优化DP)

CF 474E Pillars

题目描述

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 hihj>=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} 1n105,0d109,1ai1015

题目大意

给出一个长度为 n n n的序列 h h h和一个整数 d d d。要求找出一个子序列,使得

  • ∣ h i + 1 − h i ∣ ≥ d |h_{i+1}-h_i|\geq d hi+1hid
  • 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,hid] [ 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;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值