题意:
从原点开始,到目标点
t
a
r
g
e
t
target
target
求最少的路程。
有n个锤子,n个墙
h
[
i
]
h[i]
h[i] 第
i
i
i个锤子的位置
w
[
i
]
w[i]
w[i] 第
i
i
i面墙的位置
第
i
i
i面墙只能被第
i
i
i个锤子打碎
思路:
- 有负数点,先离散化。
- 考虑dp
d p 1 [ x ] [ y ] dp1[x][y] dp1[x][y]区间 [ x , y ] [x,y] [x,y]最后到左端点x的最小距离。
d p 2 [ x ] [ y ] dp2[x][y] dp2[x][y]区间 [ x , y ] [x,y] [x,y]最后到右端点y的最小距离。 - 转移时,要考虑
x
−
1
x-1
x−1和
y
+
1
y+1
y+1是否是墙,如果是墙,是否拿到了锤子。
d p 1 [ x − 1 ] [ y ] dp1[x-1][y] dp1[x−1][y]:
d p 2 [ x ] [ y + 1 ] dp2[x][y+1] dp2[x][y+1]
AC(JAVA)
package com.hgs.atcoder.abc.contest273.f;
/**
* @author youtsuha
* @version 1.0
* Create by 2022/10/15 19:52
*/
import java.util.*;
import java.io.*;
public class Main {
static FastScanner cin;
static PrintWriter cout;
private static void init()throws IOException {
cin = new FastScanner(System.in);
cout = new PrintWriter(System.out);
}
private static void close(){
cout.close();
}
static int lower_bound(List<Integer> ax, int v){
int L = 0, R = ax.size() - 1;
while(L < R){
int mid = L + R + 1 >> 1;
// a[mid] <= v
if(ax.get(mid).compareTo(v) <= 0) L = mid;
else R = mid - 1;
}
return L;
}
private static void sol()throws IOException {
int n = cin.nextInt(), target = cin.nextInt();
int w[] = new int[n+1];
int h[] = new int[n+1];
List<Integer> ax = new ArrayList<>();
ax.add(0);ax.add(target);
for(int i = 1; i <= n; i ++ ) {
w[i] = cin.nextInt();
ax.add(w[i]);
}
for(int i = 1; i <= n; i ++ ) {
h[i] = cin.nextInt();
ax.add(h[i]);
}
ax = new ArrayList<>(new TreeSet<>(ax));
int p0 = lower_bound(ax,0);
int sz = ax.size() - 1;
int w2h[] = new int[sz+1];
int isWall[] = new int[sz+1];
for(int i = 1; i <= n; i ++ ) {
w[i] = lower_bound(ax,w[i]);
h[i] = lower_bound(ax,h[i]);
w2h[w[i]] = h[i];
isWall[w[i]] = 1;
}
long dp1[][] = new long[sz+3][sz+3];//left:X
long dp2[][] = new long[sz+3][sz+3];//right:y
long inf = (long) 1e18;
// for(int i = 0; i <= sz; i ++ ) for(int j = 0; j <= sz; j ++ ) dp1[i][j] = dp2[i][j] = Long.MAX_VALUE;
for(int i = 0; i <= sz; i ++ ) for(int j = 0; j <= sz; j ++ ) dp1[i][j] = dp2[i][j] = inf;
dp1[p0][p0] = dp2[p0][p0] = 0;
target = lower_bound(ax,target);
long ans = inf;
for(int x = p0; x >= 0; x-- ){
for(int y = p0; y <= sz; y ++ ) {
if(x <= target && target <= y) {
ans = Math.min(ans, dp1[x][y]);
ans = Math.min(ans, dp2[x][y]);
}
if(x-1 >= 0) {
if(isWall[x-1] == 1 && w2h[x-1] >= x && w2h[x-1] <= y || isWall[x-1] == 0) {
dp1[x-1][y] = Math.min(dp1[x-1][y], dp1[x][y] + Math.abs(ax.get(x - 1) - ax.get(x)));
dp1[x-1][y] = Math.min(dp1[x-1][y], dp2[x][y] + Math.abs(ax.get(x - 1) - ax.get(y)));
}
}
if(y + 1 <= sz){
if(isWall[y+1] == 1 && w2h[y+1] >= x && w2h[y+1] <= y || isWall[y+1] == 0) {
dp2[x][y+1] = Math.min(dp2[x][y+1], dp1[x][y] + Math.abs(ax.get(x) - ax.get(y+1)));
dp2[x][y+1] = Math.min(dp2[x][y+1], dp2[x][y] + Math.abs(ax.get(y) - ax.get(y+1)));
}
}
}
}
cout.println(inf == ans?-1:ans);
}
public static void main(String[] args) throws IOException {
init();
sol();
close();
}
}
class FastScanner {
BufferedReader br;
StringTokenizer st = new StringTokenizer("");
public FastScanner(InputStream s) {
br = new BufferedReader(new InputStreamReader(s));
}
public FastScanner(String s) throws FileNotFoundException {
br = new BufferedReader(new FileReader(new File(s)));
}
public String next() throws IOException {
while (!st.hasMoreTokens()){
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) { e.printStackTrace(); }
}
return st.nextToken();
}
public int nextInt() throws IOException {
return Integer.parseInt(next());
}
public long nextLong() throws IOException {
return Long.parseLong(next());
}
public double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}