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 pillarsi2, ..., 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,满足num[i]<num[j]。线段树中每个区间保存区间内的最大长度以及最大长度对应的结尾元素标号。然后我们从左到右处理每个点(未离散化之前的点),对于第i个点,设其高度为num[i],则我们在高度1~num[i]-K(即线段树的(1,Lfind(num[i])内找到一个最长长度,在num[i]+K~N,即线段树的(Rfind(num[i],cur)内找到一个最长长度,取最优的一个,长度+1用以更新当前点,同时记录前驱。最后再递归输出就行了。
代码:
//156ms
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=1e5+10;
int pre[maxn];//记录前一个点
long long num[maxn];
long long a[maxn];
int cur;
struct node
{
int maxcou;//以这个高度结尾的最大长度
int pos;//以这个高度结尾的元素的位置
}tree[maxn<<2];
void build(int rt,int l,int r)
{
if(l==r)
{
tree[rt].maxcou=0;
tree[rt].pos=0;
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
tree[rt].maxcou=0;
tree[rt].pos=0;
}
int Rfind ( long long x ) {
int l = 1 , r = cur ;
while ( l < r ) {
int m = ( l + r ) / 2 ;
if ( a[m] >= x ) r = m ;
else l = m + 1 ;
}
return l ;
}
int Lfind ( long long x ) {
int l = 1 , r = cur ;
while ( l < r ) {
int m = ( l + r + 1 ) / 2 ;
if ( a[m] <= x ) l = m ;
else r = m - 1 ;
}
return r ;
}
void update(int x,int v,int i,int rt,int l,int r)
{
if(l==r)
{
if(v>tree[rt].maxcou)
{
tree[rt].maxcou=v;
tree[rt].pos=i;
}
return;
}
int mid=(l+r)>>1;
if(x<=mid)
update(x,v,i,rt<<1,l,mid);
else
update(x,v,i,rt<<1|1,mid+1,r);
if(tree[rt<<1].maxcou>tree[rt<<1|1].maxcou)
{
tree[rt].maxcou=tree[rt<<1].maxcou;
tree[rt].pos=tree[rt<<1].pos;
}
else
{
tree[rt].maxcou=tree[rt<<1|1].maxcou;
tree[rt].pos=tree[rt<<1|1].pos;
}
}
int maxcount,maxpos;
void query(int L,int R,int rt,int l,int r)
{
if(L>R)
return;
if(L<=l&&R>=r)
{
if(tree[rt].maxcou>maxcount)
{
maxcount=tree[rt].maxcou;
maxpos=tree[rt].pos;
}
return;
}
int mid=(l+r)>>1;
if(L<=mid)
query(L,R,rt<<1,l,mid);
if(R>mid)
query(L,R,rt<<1|1,mid+1,r);
}
void prin(int u)
{
if(pre[u]!=0)
{
prin(pre[u]);
printf("%d ",pre[u]);
}
return;
}
int main()
{
int n,k,ids=1,ans=1;
scanf("%d%d",&n,&k);
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++)
{
scanf("%I64d",&num[i]);
a[i]=num[i];
}
sort(a+1,a+n+1);
cur=1;
for(int i=2;i<=n;i++)//离散化,以元素的个数来建树,每个叶子节点代表一个高度
if(a[i]!=a[cur])
{
a[++cur]=a[i];
}
build(1,1,cur);
update(Lfind(num[1]),1,1,1,1,cur);
pre[1]=0;
for(int i=2;i<=n;i++)
{
int L=Lfind(num[i]-k);//小于num[i]-k的最大位置
int R=Rfind(num[i]+k);//大于num[i]+k的最小位置
maxcount=0,maxpos=0;
if(a[L]+k<=num[i])
{
query(1,L,1,1,cur);
}
if(num[i]+k<=a[R])
{
query(R,cur,1,1,cur);
}
update(Lfind(num[i]),maxcount+1,i,1,1,cur);
pre[i]=maxpos;
if(maxcount+1>ans)
{
ans=maxcount+1;
ids=i;
}
}
printf("%d\n",ans);
prin(ids);
printf("%d\n",ids);
return 0;
}
在CF看到的一个投机取巧的方法,数据也很难出到这么强,在比赛的时候可以水一发。
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
const int maxn=100000+100;
using namespace std;
int main() {
int n, d;
scanf("%d%d",&n,&d);
long long h[maxn];
int z[maxn],p[maxn];
for(int i=0; i<n; i++)
scanf("%I64d",&h[i]);
for(int i=0; i<n; i++)
{
z[i]=1;
}
for(int i=1; i<n; i++){
for(int j=max(0,i-300); j<i; j++){
if( abs(h[i]-h[j])>=d && z[j]+1>z[i]){
z[i]=z[j]+1;
p[i]=j;
}
}
}
int max=-100,index;
for(int i=0; i<n; i++)
{
if(z[i]>max) {
max=z[i];
index=i;
}
}
printf("%d\n",max);
vector <int> a;
a.push_back(index);
max--;
while(max>0){
index=p[index];
a.push_back(index);
max--;
}
for(int i=a.size()-1; i>=0; i--)
{
printf("%d ",a[i]+1);
}
}