E. Pillars(Codeforces Round #271)

E. Pillars
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Input

The first line contains two integers n and d (1 ≤ n ≤ 1050 ≤ d ≤ 109).

The second line contains n numbers h1, h2, ..., hn (1 ≤ hi ≤ 1015).

Output

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 test(s)
input
5 2
1 3 6 7 4
output
4
1 2 3 5 
input
10 3
2 1 3 6 9 11 7 3 20 18
output
6
1 4 6 7 8 9 
Note

In the first example Marmot chooses the pillars 1235 with the heights 1364. Another jump sequence of length 4 is 1245.


因为一个字母写错,纠结了几天难过

首先将高度排序离散化,以离散化后的元素个数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);
		}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值