链接:戳这里
E. Pillars
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard 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 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.
Input
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).
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.
Examples
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 1, 2, 3, 5 with the heights 1, 3, 6, 4. Another jump sequence of length 4 is 1, 2, 4, 5.
题意:
有n根柱子,每根柱子高度为hi。人当前在第j根柱子,可以跳到前面的任意第i根柱子,只需要满足|aj-ai|>=d
问最多能跳多少根柱子。输出答案,并输出答案跳的路径
思路:
很容易想到dp[i]:表示当前第i根柱子的最优值
那么dp[i]肯定是从前面的dp[1~j] (1<=j<i)的最优值里面继承过来,类于LIS的On*n思想,但是这样会T
考虑我们需要快速找出(1~j)中的满足,aj-ai>=d || ai-aj>=d 的最大值dp[j],发现是找出两个区间的最大值
线段树下标从小到大存柱子的高度顺序(注意是高度大小顺序),由于高度太大,这里需要离散化一下。
线段树存两个权值,分别是当前区间的最大值dp[l,r]以及当前区间最大值所在的原hi数组的下标,方便记录路径
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
int n;
ll d;
ll a[100100],b[100100];
int dp[100100],pre[100100];
int tr[400100],id[400100];
void build(int root,int l,int r){
if(l==r) {
tr[root]=0;
return ;
}
int mid=(l+r)/2;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
}
pair<int,int> query(int root,int l,int r,int x,int y){
if(x<=l &&y>=r){
return make_pair(tr[root],id[root]);
}
int mid=(l+r)/2;
pair<int,int> ans;
ans=make_pair(0,0);
if(x<=mid){
pair<int,int> tmp=query(root*2,l,mid,x,y);
if(ans.first<tmp.first){
ans=tmp;
}
}
if(y>mid){
pair<int,int> tmp=query(root*2+1,mid+1,r,x,y);
if(ans.first<tmp.first){
ans=tmp;
}
}
if(tr[root*2]>=tr[root*2+1]){
tr[root]=tr[root*2];
id[root]=id[root*2];
} else {
tr[root]=tr[root*2+1];
id[root]=id[root*2+1];
}
return ans;
}
void update(int root,int l,int r,int pos,int i,int v){
if(l==pos && r==pos){
if(tr[root]<v){
tr[root]=v;
id[root]=i;
}
return ;
}
int mid=(l+r)/2;
if(pos<=mid){
update(root*2,l,mid,pos,i,v);
} else if(pos>mid) update(root*2+1,mid+1,r,pos,i,v);
if(tr[root*2]>=tr[root*2+1]){
tr[root]=tr[root*2];
id[root]=id[root*2];
} else {
tr[root]=tr[root*2+1];
id[root]=id[root*2+1];
}
}
void print(int x){
if(x==0) return ;
else print(pre[x]);
printf("%d ",x);
}
int main(){
scanf("%d%I64d",&n,&d);
for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
for(int i=1;i<=n;i++) b[i]=a[i];
sort(b+1,b+n+1);
int m=unique(b+1,b+n+1)-(b+1);
build(1,1,m);
int ans=0,root=-1;
for(int i=1;i<=n;i++){
dp[i]=0;
int L=upper_bound(b+1,b+m+1,a[i]-d)-b;
int R=lower_bound(b+1,b+m+1,a[i]+d)-b;
L--;
if(L>=1){
pair<int ,int> p=query(1,1,m,1,L);
if(p.first+1>dp[i]){
dp[i]=p.first+1;
pre[i]=p.second;
}
}
if(R<=m){
pair<int,int> p=query(1,1,m,R,m);
if(p.first+1>dp[i]){
dp[i]=p.first+1;
pre[i]=p.second;
}
}
int x=lower_bound(b+1,b+m+1,a[i])-b;
update(1,1,m,x,i,dp[i]);
if(ans<dp[i]){
ans=dp[i];
root=i;
}
}
printf("%d\n",ans);
if(ans==0) return 0;
print(root);
return 0;
}

解决一道算法题目,通过动态规划和线段树实现寻找最长跳跃序列,包括代码实现和思路解析。
362

被折叠的 条评论
为什么被折叠?



