Marmot found a row with n pillars. The i-th pillar has the height of hi meters. Starting from one pillar i1, Marmot wants to jump on the pillars i2, ..., ik. (1 ≤ i1 < i2 < ... < ik ≤ n). From a pillar i Marmot can jump on a pillar j only if i < j and |hi - hj| ≥ d, where |x| is the absolute value of the number 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 ≤ 105, 0 ≤ d ≤ 109).
The second line contains n numbers h1, h2, ..., hn (1 ≤ hi ≤ 1015).
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.
5 2 1 3 6 7 4
4 1 2 3 5
10 3 2 1 3 6 9 11 7 3 20 18
6 1 4 6 7 8 9
In the first example Marmot chooses the pillars 1, 2, 3, 5 with the heights 1, 3, 6, 4. Another jump sequence of length 4 is 1, 2, 4, 5.
题目大意:
给你N个数的序列,现在让你找到一个点作为起点,向后跳,希望跳的最远,让你找到这个长度,以及一条路径。
从点i能够跳到点j的条件是:i<j&&|a[i]-a[j]|>=d;
思路:
1、这种题很套路啊,我们肯定这个题一定是dp题咯,那么设定dp【i】=x表示以a【i】结尾的最长子序列长度是x。
那么状态转移方程有:dp【i】=max(1,dp【j】+1)【1<=j<i&&|a[i]-a[j]|>=d】
然而我们暴力去跑这个dp的话,肯定要超时的、那么考虑线段树优化(这种题很套路,做多了一下子就能想到了);
使得有:
dp【i】=1;
dp【i】=max(dp【i】,max【1,a[i]-d-1】);
dp【i】=max(dp【i】,max【a[i]+d+1,inf】);
如果问题中a【i】比较小的话,那么肯定我们可以直接套线段树维护即可。
但是这里a【i】比较大,那么我们肯定是需要离散化的,再考虑到a【i】的值是会重复的,那么我们一定要注意离散化的时候不能只根据值来离散化。
那么离散化之后,线段树上第i个元素就表示第i大的元素所保存的值。
那么我们在区间查询的时候,要二分两个点.然后再进行查询(因为此时我们已知的信息是每个值是第几大)。
过程谨慎一点去实现,然后每一次搞定了dp【i】之后,将dp【i】更新入树即可。
2、搞定了dp问题之后,max(dp【i】)【1<=i<=n】就是最长子序列的长度。
那么如何搞定路径问题呢?
我们考虑在查询区间最大值的同时,查询这个最大值的位子,如果dp【i】可以被查询所更新,那么我们记录pre【i】=之前那个位子即可。
过程维护一下pre【i】,输出结果的时候,回溯一下并逆序输出路径即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<climits>
#include<map>
#include<algorithm>
using namespace std;
#define ll __int64
#define lson l, m, rt<<1
#define rson m+1, r, (rt<<1)|1
struct node
{
ll val,pos;
}tmp[105000];
ll cmp(node a,node b)
{
return a.val<b.val;
}
ll tree[111111*4];
ll posn[111111*4];
ll pre[111111];
ll output[111111];
void pushup(ll rt)
{
if (tree[rt<<1] > tree[rt<<1|1])
{
tree[rt] = tree[rt<<1];
posn[rt] = posn[rt<<1];
}
else
{
tree[rt] = tree[rt<<1|1];
posn[rt] = posn[rt<<1|1];
}
}
void build(ll l, ll r, ll rt)
{
if (l == r)
{
tree[rt]=0;
posn[rt] = l;
}
else
{
ll m = (l + r) >> 1;
build(lson);
build(rson);
pushup(rt);
}
}
void update(ll p, ll val, ll l, ll r, ll rt)
{
if (l == r)
{
tree[rt] = val;
}
else
{
ll m = (l + r) >> 1;
if (p <= m)
{
update(p, val, lson);
}
else
{
update(p, val, rson);
}
pushup(rt);
}
}
ll query(ll L, ll R, ll l, ll r, ll rt, ll *pos)
{
if (L <= l && r <= R)
{
*pos = posn[rt];
return tree[rt];
}
else
{
ll m = (l + r) >> 1;
ll ret1 = INT_MIN;
ll ret2 = INT_MIN;
ll pa, pb;
ll *pos1 = &pa;
ll *pos2 = &pb;
if (L <= m)
{
ret1 = query(L, R, lson, pos1);
}
if (R > m)
{
ret2 = query(L, R, rson, pos2);
}
if (ret1 > ret2)
{
*pos = pa;
}
else
{
*pos = pb;
ret1 = ret2;
}
return ret1;
}
}
ll dp[108000];
ll a[108000];
int main()
{
ll n,d;
while(~scanf("%I64d%I64d",&n,&d))
{
map<ll ,ll >s;
memset(pre,-1,sizeof(pre));
for(ll i=1;i<=n;i++)scanf("%I64d",&a[i]),tmp[i].val=a[i],tmp[i].pos=i;
sort(tmp+1,tmp+1+n,cmp);
for(ll i=1;i<=n;i++)
{
s[tmp[i].pos]=i;
}
build(1,n,1);
for(ll i=1;i<=n;i++)
{
if(i==1)dp[i]=1;
else
{
dp[i]=1;
ll l=1;
ll r=s[i];
ll posl=r;
while(r-l>=0)
{
ll mid=(l+r)/2;
if(tmp[mid].val>a[i]-d)
{
posl=mid;
r=mid-1;
}
else l=mid+1;
}
l=s[i];
r=n;
ll posr=l;
while(r-l>=0)
{
ll mid=(l+r)/2;
if(tmp[mid].val<a[i]+d)
{
posr=mid;
l=mid+1;
}
else r=mid-1;
}
ll temp;
if(posl-1>=1)
{
if(query(1,posl-1,1,n,1,&temp)+1>dp[i])
{
dp[i]=query(1,posl-1,1,n,1,&temp)+1;
pre[i]=tmp[temp].pos;
}
}
if(n>=posr+1)
{
if(query(posr+1,n,1,n,1,&temp)+1>dp[i])
{
dp[i]=query(posr+1,n,1,n,1,&temp)+1;
pre[i]=tmp[temp].pos;
}
}
}
update(s[i],dp[i],1,n,1);
}
ll maxn=0;
ll anspos=0;
for(ll i=1;i<=n;i++)
{
if(dp[i]>maxn)maxn=dp[i],anspos=i;
}
printf("%I64d\n",maxn);
int cnt=0;
while(anspos>=1)
{
output[cnt++]=anspos;
anspos=pre[anspos];
}
for(int i=cnt-1;i>=0;i--)
{
printf("%I64d ",output[i]);
}
printf("\n");
}
}