結果

問題 No.705 ゴミ拾い Hard
ユーザー 草苺奶昔草苺奶昔
提出日時 2023-12-03 00:38:30
言語 Go
(1.22.1)
結果
AC  
実行時間 447 ms / 1,500 ms
コード長 4,405 bytes
コンパイル時間 13,590 ms
コンパイル使用メモリ 214,284 KB
実行使用メモリ 18,356 KB
最終ジャッジ日時 2023-12-03 00:38:55
合計ジャッジ時間 24,650 ms
ジャッジサーバーID
(参考情報)
judge11 / judge13
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,676 KB
testcase_01 AC 2 ms
6,676 KB
testcase_02 AC 1 ms
6,676 KB
testcase_03 AC 1 ms
6,676 KB
testcase_04 AC 1 ms
6,676 KB
testcase_05 AC 1 ms
6,676 KB
testcase_06 AC 1 ms
6,676 KB
testcase_07 AC 1 ms
6,676 KB
testcase_08 AC 1 ms
6,676 KB
testcase_09 AC 1 ms
6,676 KB
testcase_10 AC 1 ms
6,676 KB
testcase_11 AC 1 ms
6,676 KB
testcase_12 AC 1 ms
6,676 KB
testcase_13 AC 1 ms
6,676 KB
testcase_14 AC 3 ms
6,676 KB
testcase_15 AC 2 ms
6,676 KB
testcase_16 AC 3 ms
6,676 KB
testcase_17 AC 3 ms
6,676 KB
testcase_18 AC 2 ms
6,676 KB
testcase_19 AC 3 ms
6,676 KB
testcase_20 AC 2 ms
6,676 KB
testcase_21 AC 2 ms
6,676 KB
testcase_22 AC 2 ms
6,676 KB
testcase_23 AC 3 ms
6,676 KB
testcase_24 AC 421 ms
18,308 KB
testcase_25 AC 441 ms
18,308 KB
testcase_26 AC 418 ms
18,312 KB
testcase_27 AC 417 ms
18,308 KB
testcase_28 AC 447 ms
18,308 KB
testcase_29 AC 433 ms
18,312 KB
testcase_30 AC 423 ms
18,264 KB
testcase_31 AC 410 ms
18,204 KB
testcase_32 AC 412 ms
18,212 KB
testcase_33 AC 305 ms
13,984 KB
testcase_34 AC 336 ms
13,984 KB
testcase_35 AC 346 ms
16,112 KB
testcase_36 AC 381 ms
18,204 KB
testcase_37 AC 338 ms
16,112 KB
testcase_38 AC 404 ms
18,204 KB
testcase_39 AC 390 ms
18,204 KB
testcase_40 AC 1 ms
6,676 KB
testcase_41 AC 1 ms
6,676 KB
testcase_42 AC 1 ms
6,676 KB
testcase_43 AC 431 ms
18,356 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	Yuki705()
}

// https://yukicoder.me/problems/no/705
func Yuki705() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var n int
	fmt.Fscan(in, &n)
	A := make([]int, n)
	X := make([]int, n)
	Y := make([]int, n)
	for i := 0; i < n; i++ {
		fmt.Fscan(in, &A[i])
	}
	for i := 0; i < n; i++ {
		fmt.Fscan(in, &X[i])
	}
	for i := 0; i < n; i++ {
		fmt.Fscan(in, &Y[i])
	}
	f := func(i, j int) int {
		a := A[j-1]
		x := X[i]
		y := Y[i]
		dx := abs(a - x)
		dy := abs(y)
		return dx*dx*dx + dy*dy*dy
	}
	fmt.Fprintln(out, MongeShortestPath(n, f)[n])
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

const INF int = 1e18

// Monge图最短路.求从0点出发到各个点的最短路.
// O(nlogn).
// https://noshi91.hatenablog.com/entry/2023/02/18/005856
func MongeShortestPath(n int, f func(i, j int) int) []int {
	dp := make([]int, n+1)
	for i := range dp {
		dp[i] = INF
	}
	x := make([]int, n+1)

	check := func(from, to int) {
		if from >= to {
			return
		}
		cost := f(from, to)
		if tmp := dp[from] + cost; tmp < dp[to] {
			dp[to] = tmp
			x[to] = from
		}
	}

	var dfs func(int, int)
	dfs = func(l, r int) {
		if l+1 >= r {
			return
		}
		m := (l + r) / 2
		for i := x[l]; i <= x[r]; i++ {
			check(i, m)
		}
		dfs(l, m)
		for i := l + 1; i <= m; i++ {
			check(i, r)
		}
		dfs(m, r)
	}
	dp[0] = 0
	check(0, n)
	dfs(0, n)
	return dp
}

// Monge图d边最短路.
// O(nlogn)求从0到n-1恰好经过d条边的最短路,其中边权f(from,to)满足Monge性质.
// f(i,j) : 边权函数, 即从i到j的边的权值(i<j).
// maxWeight: 边权的最大值.
// 返回值为从0到N恰好经过d条边的最短路.
func MongeShortestPathDEdge(n, d, maxWeight int, f func(i, j int) int) int {
	if d > n {
		panic("d > N")
	}
	cal := func(x int) int {
		g := func(frm, to int) int {
			return f(frm, to) + x
		}
		cost := MongeShortestPath(n, g)[n]
		return cost - x*d
	}
	_, res := FibonacciSearch(cal, -3*maxWeight, 3*maxWeight+1, false)
	return res
}

// monge图d边最短路的d=1,...,N的答案.
// 无法到达的点的距离为INF.
// f(i,j) : 边权函数, 即从i到j的边的权值(i<j).
func EnumerateMongeDEdgeShortestPath(n int, f func(i, j int) int) []int {
	res := make([]int, n+1)
	for i := range res {
		res[i] = INF
	}
	dp := make([]int, n+1)
	for i := range dp {
		dp[i] = INF
	}
	dp[0] = 0
	for d := 1; d <= n; d++ {
		midx := MonotoneMinima2(n+1, n+1, func(j, i int) int {
			if i < j {
				return dp[i] + f(i, j)
			}
			return INF
		})
		for i := n; i >= d; i-- {
			dp[i] = dp[midx[i]] + f(midx[i], i)
		}
		res[d] = dp[n]
	}
	return dp
}

// 给定一个 n 行 m 列的矩阵.
// minI=argmin_j(A[i][j]) 单调递增时, 返回 minI.
// f(i, j, k) :
// 比较 A[i][j] 和 A[i][k] (保证 j < k)
// 当 A[i][j] <= A[i][k] 时返回 true.
func MonotoneMinima(row, col int, f func(i, j, k int) bool) []int {
	res := make([]int, row)
	var dfs func(int, int, int, int)
	dfs = func(is, ie, l, r int) {
		if is == ie {
			return
		}
		i := (is + ie) / 2
		m := l
		for k := l + 1; k < r; k++ {
			if !f(i, m, k) {
				m = k
			}
		}
		res[i] = m
		dfs(is, i, l, m+1)
		dfs(i+1, ie, m, r)
	}
	dfs(0, row, 0, col)
	return res
}

// 给定一个 n 行 m 列的矩阵.
// minI=argmin_j(A[i][j]) 单调递增时, 返回 minI.
// get(i, j) : 返回 A[i][j] 的函数
func MonotoneMinima2(row, col int, get func(i, j int) int) []int {
	f := func(i, j, k int) bool {
		return get(i, j) <= get(i, k)
	}
	return MonotoneMinima(row, col, f)
}

// 寻找[start,end)中的一个极值点,不要求单峰性质.
//
//	返回值: (极值点,极值)
func FibonacciSearch(f func(x int) int, start, end int, minimize bool) (int, int) {
	end--
	a, b, c, d := start, start+1, start+2, start+3
	n := 0
	for d < end {
		b = c
		c = d
		d = b + c - a
		n++
	}

	get := func(i int) int {
		if end < i {
			return INF
		}
		if minimize {
			return f(i)
		}
		return -f(i)
	}

	ya, yb, yc, yd := get(a), get(b), get(c), get(d)
	for i := 0; i < n; i++ {
		if yb < yc {
			d = c
			c = b
			b = a + d - c
			yd = yc
			yc = yb
			yb = get(b)
		} else {
			a = b
			b = c
			c = a + d - b
			ya = yb
			yb = yc
			yc = get(c)
		}
	}

	x := a
	y := ya
	if yb < y {
		x = b
		y = yb
	}
	if yc < y {
		x = c
		y = yc
	}
	if yd < y {
		x = d
		y = yd
	}

	if minimize {
		return x, y
	}
	return x, -y

}
0