洛谷P10726 [GESP202406 八级] 空间跳跃 题解
题目传送门。
第一次自己做出一道绿色的 DP!!!!
刚开始的时候,你会发现这其实就是一个很朴素的 DP,一开始先按高度将挡板从小到大排序,然后将 \(s\) 和 \(t\) 更改为排序后的位置,设 \(f_{i,j}\) 表示当前在第 \(i\) 个档板的 \(j\) 位置到达第 \(t\) 号挡板的最短距离,然后状态转移为 \(f_{i,j} = \min(f_{k,l_i}+h_i-h_k+j-l_i,f_{o,r_i}+h_i-h_o+r_i-j)\),\(k\) 就是能从 \(l_i\) 掉落到的挡板编号,\(o\) 是能从 \(r_i\) 掉落到的挡板编号,虽然正确,但是你会发现时间复杂度原地起飞,通过十分困难,不过洛谷机子这么好应该能过,但是你会发现其实你每次掉落你的位置只会在 \(l_i,r_i\) 中,所以最多只需要将所有的 \(l_i,r_i\) 当做 DP 数组的第二维求就行了,所以空间复杂度和时间复杂度就都全部降下来了,然后这题就做完了……
由于本人很唐,所以找到能掉落挡板位置的方法比较唐氏,就是使用区间覆盖最大值的方法,当然也可以直接往前找,时间复杂度差别应该只是个常数。
注意事项:
- 记得特判 \(s<t\) 的情况!!
- 记得特判不能转移的情况!!
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e3+5;
int f[N][N];
struct node
{
int l;
int r;
int h;
int id;
}a[N];
int cmp(node x,node y)
{
return x.h<y.h;
}
int ans[N];
int maxx[N];
signed main()
{
memset(f,0x3f,sizeof(f));
int n,s,t,cnt = 0;
scanf("%d %d %d",&n,&s,&t);
for(int i = 1;i<=n;i++)
{
scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].h);
a[i].id = i;
ans[++cnt] = a[i].l;
ans[++cnt] = a[i].r;
}
sort(ans+1,ans+cnt+1);
sort(a+1,a+n+1,cmp);
for(int i = 1;i<=n;i++)
{
if(a[i].id == s)
{
s = i;
}
if(a[i].id == t)
{
t = i;
}
}
if(s<t)
{
printf("-1");
return 0;
}
int l = lower_bound(ans+1,ans+cnt+1,a[t].l)-ans;
int r = upper_bound(ans+1,ans+cnt+1,a[t].r)-ans-1;
for(int i = l;i<=r;i++)
{
f[t][i] = 0;
}
for(int i = t+1;i<=s;i++)
{
int l = lower_bound(ans+1,ans+cnt+1,a[i-1].l)-ans;
int r = upper_bound(ans+1,ans+cnt+1,a[i-1].r)-ans-1;
for(int j = l;j<=r;j++)
{
maxx[j] = max(maxx[j],i-1);
}
int ll = lower_bound(ans+1,ans+cnt+1,a[i].l)-ans;
int rr = upper_bound(ans+1,ans+cnt+1,a[i].r)-ans-1;
int lll = maxx[ll];
int rrr = maxx[rr];
for(int j = ll;j<=rr;j++)
{
if(lll!=0)//找不到掉落到的挡板不能进行转移
{
f[i][j] = min(f[i][j],ans[j]-a[i].l+a[i].h-a[lll].h+f[lll][ll]);
}
if(rrr!=0)//找不到掉落到的挡板不能进行转移
{
f[i][j] = min(f[i][j],a[i].r-ans[j]+a[i].h-a[rrr].h+f[rrr][rr]);
}
}
}
int weizhi = lower_bound(ans+1,ans+cnt+1,a[s].l)-ans;
printf("%d",f[s][weizhi] == f[0][0]?-1:f[s][weizhi]);
return 0;
}
所以说这题有绿吗,我怎么感觉暴力 DP 能过???虽然没试过……

浙公网安备 33010602011771号