题意:
给出一个序列,一次跳跃只能从i跳到j,满足j>i同时abs(a[j]-a[i])>=d。询问最多可以跳几次,输出路径。
题解:
做过很多次的DP模型,需要注意的是这里的值域是1e15,需要先对数据做一个离散化,然后二分出每步DP的上下界。保存DP路径的细节在线段树和状态转移的过程中都有体现,属于常见套路!
/* *author: zlc *zucc_acm_lab *just do it */ #include<bits/stdc++.h> using namespace std; typedef long long ll; const double pi=acos(-1.0); const double eps=1e-6; const int mod=1e9+7; const int inf=1e9; const int maxn=2e5+100; inline ll read () {ll x=0,f=1;char ch=getchar();while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return x*f;} ll qpow (ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} ll n,d; ll a[maxn]; ll t[maxn]; ll dp[maxn]; ll pre[maxn]; struct node { int l,r; pair<ll,ll> sum; }segTree[maxn<<2]; void build (int i,int l,int r) { segTree[i].l=l; segTree[i].r=r; segTree[i].sum.first=-1; segTree[i].sum.second=-1; if (l==r) { return; } int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); segTree[i].sum=max(segTree[i<<1].sum,segTree[i<<1|1].sum); } void up (int i,ll p,ll v,ll pre) { if (segTree[i].l==p&&segTree[i].r==p) { segTree[i].sum=max(segTree[i].sum,make_pair(v,pre)); return; } ll mid=(segTree[i].l+segTree[i].r)>>1; if (p<=mid) up(i<<1,p,v,pre); if (p>mid) up(i<<1|1,p,v,pre); segTree[i].sum=max(segTree[i<<1].sum,segTree[i<<1|1].sum); } pair<ll,ll> query (int i,int l,int r) { if (l>r) return make_pair(-1ll,-1ll); if (segTree[i].l>=l&&segTree[i].r<=r) return segTree[i].sum; int mid=(segTree[i].l+segTree[i].r)>>1; pair<ll,ll> ans=make_pair(0ll,0ll); if (l<=mid) ans=max(ans,query(i<<1,l,r)); if (r>mid) ans=max(ans,query(i<<1|1,l,r)); return ans; } int main () { n=read(),d=read(); for (int i=1;i<=n;i++) a[i]=read(),t[i]=a[i]; sort(t+1,t+n+1); int m=unique(t+1,t+n+1)-t-1; for (int i=1;i<=n;i++) a[i]=upper_bound(t+1,t+m+1,a[i])-t-1; //for (int i=1;i<=n;i++) printf("%lld ",a[i]);printf("\n"); build(1,1,m+1); for (int i=1;i<=n;i++) { int Min=upper_bound(t+1,t+m+1,t[a[i]]-d)-t; int Max=lower_bound(t+1,t+m+1,t[a[i]]+d)-t; Min--; pair<ll,ll> t1=query(1,1,Min); if (t1.first+1>dp[i]) { dp[i]=t1.first+1; pre[i]=t1.second; } pair<ll,ll> t2=query(1,Max,m); if (t2.first+1>dp[i]) { dp[i]=t2.first+1; pre[i]=t2.second; } up(1,a[i],dp[i],i); } ll ans=0,u=-1; for (int i=1;i<=n;i++) { if (dp[i]>ans) { ans=dp[i]; u=i; } } printf("%lld\n",ans); vector<int> wjm; while (u) { wjm.push_back(u); u=pre[u]; } reverse(wjm.begin(),wjm.end()); for (int v:wjm) printf("%d ",v); printf("\n"); }