Treasure Hunting
分析:
题目中一个很关键的条件就是不能向下走
也就确定了我们这一题要一行一行去转移状态。
这意思是,当我们走到第i行的时候,第i行之前的宝藏已经全部被拿掉了。
当我们走第i行的时候,我们也需要把第i行的宝藏全部拿掉。
这个时候我们发现,由于我们处在第i行的时候,我们需要把这一行的宝藏全部拿掉,所以我们只需要关心第i行最靠左/右的宝藏位置即可
这也就确定了我们的dp状态:
f
[
i
]
[
0
/
1
]
f[i][0/1]
f[i][0/1]表示我们当前处在第i行左边/右边的最小步数是多少。
当前的状态可以从前一行的0/1转移过来
还有一点就是传送阵的位置,对当前位置,需要枚举里当前位置最近的左/右传送阵的位置,一次从前面的位置转移过来。
转移过来的时候需要往上走,所以还需要步数+1
还有一点需要注意的就是如果当前位置没有宝藏,那么当前位置就继承上一个位置的宝藏,同时步数+1,意思就是上一层的宝藏往上平移。
细节有点多,代码量有点大。
写的时候有点头晕(
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+100;
int n,m,k,q;
int Min[N],Max[N];
vector < int > a[N];
int l[N];
int f[N][3];
#define pb push_back
int Find(int x){
int ll = 1 , r = q;
while (ll+1<r){
int Mid = ll+r>>1;
if (l[Mid] >= x) r = Mid; else ll = Mid;
}
if (l[r] < x) return r; else return ll;
}
signed main(){
cin>>n>>m>>k>>q;
for (int i = 1; i <= n; i++) Min[i] = m+1;
for (int i = 1; i <= k; i++){
int x,y;
cin>>x>>y;
Min[x] = min(Min[x],y); Max[x] = max(Max[x],y);
}
for (int i = 1; i <= n; i++) if (Max[i]!=0) a[i].pb(Min[i]),a[i].pb(Max[i]);
for (int i = 1; i <= q; i++) cin>>l[i];
sort(l+1,l+q+1);
int Maxh = 0;
a[0].pb(1); a[0].pb(1);
for (int i = 1; i <= n; i++) if (a[i].size()) Maxh = i;
for (int i = 1; i <= n; i++) if (a[i].size() == 1) a[i].pb(a[i][0]);
for (int i = 1; i <= n; i++)
if (a[i].size()) sort(a[i].begin(),a[i].end());
if (a[1].size() == 0) a[1] = a[0];
if (a[1].size() >= 2){
f[1][0] = a[1][a[1].size()-1]-1+a[1][a[1].size()-1]-a[1][0]; f[1][1] = a[1][a[1].size()-1]-1;
}
for (int i = 2; i <= Maxh; i++){
if (a[i].size() == 0){
a[i] = a[i-1];
f[i][0] = f[i-1][0]+1; f[i][1] = f[i-1][1]+1;
continue;
}
int now1 = a[i][0] , now2 = a[i][a[i].size()-1]; int la1 = a[i-1][0] , la2 = a[i-1][a[i-1].size()-1];
int po = Find(now2); int Po = l[po]; int s1 = f[i-1][0]+abs(la1-Po)+abs(Po-now2)+now2-a[i][0];
if (po < q) Po = l[po+1]; int s2 = f[i-1][0]+abs(la1-Po)+abs(Po-now2)+now2-a[i][0];
f[i][0] = min(s1,s2);
Po = l[po];
s1 = f[i-1][1]+abs(la2-Po)+abs(Po-now2)+now2-a[i][0];
if (po < q) Po = l[po+1];
s2 = f[i-1][1]+abs(la2-Po)+abs(Po-now2)+now2-a[i][0];
s1 = min(s1,s2); f[i][0] = min(f[i][0],s1);
po = Find(now1); Po = l[po];
s1 = f[i-1][0]+abs(la1-Po)+abs(Po-a[i][0])+now2-a[i][0];
if (po < q) Po = l[po+1];
s2 = f[i-1][0]+abs(la1-Po)+abs(Po-a[i][0])+now2-a[i][0];
f[i][1] = min(s1,s2);
Po = l[po];
s1 = f[i-1][1]+abs(la2-Po)+abs(Po-a[i][0])+now2-a[i][0];
if (po < q) Po = l[po+1];
s2 = f[i-1][1]+abs(la2-Po)+abs(Po-a[i][0])+now2-a[i][0];
s1 = min(s1,s2); f[i][1] = min(f[i][1],s1);
f[i][0]++; f[i][1]++;
}
cout<<min(f[Maxh][0],f[Maxh][1]);
return 0;
}
/*
5 5 10 3
3 1
3 2
3 5
1 5
2 1
2 5
1 2
1 4
3 3
2 4
2 1 5
*/