結果
問題 |
No.2596 Christmas Eve (Heuristic ver.)
|
ユーザー |
![]() |
提出日時 | 2025-03-11 12:18:07 |
言語 | Go (1.23.4) |
結果 |
AC
|
実行時間 | 1,206 ms / 1,224 ms |
コード長 | 11,271 bytes |
コンパイル時間 | 12,419 ms |
コンパイル使用メモリ | 240,220 KB |
実行使用メモリ | 19,068 KB |
スコア | 4,960,723 |
最終ジャッジ日時 | 2025-03-11 12:21:03 |
合計ジャッジ時間 | 175,076 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 125 |
ソースコード
package main import ( "cmp" . "fmt" "math" "math/rand" "slices" "sort" "time" ) type Unit struct { Id, Width, Height int } func solve(n, k int, a, b, c, d, e, f []int) (res [][]int) { ch := time.After(1180 * time.Millisecond) tops := make([]*Unit, n) for i := range tops { tops[i] = &Unit{ Id: i+1, Width: a[i], Height: b[i], } } leaves := make([]*Unit, n*2) for i := range leaves { leaves[i] = &Unit{ Id: i+1, Width: c[i], Height: d[i], } } trunks := make([]*Unit, n) for i := range trunks { trunks[i] = &Unit{ Id: i+1, Width: e[i], Height: f[i], } } slices.SortFunc(tops, func(a, b *Unit) int { return cmp.Compare(a.Width, b.Width) }) slices.SortFunc(leaves, func(a, b *Unit) int { return cmp.Compare(a.Width, b.Width) }) slices.SortFunc(trunks, func(a, b *Unit) int { return cmp.Compare(a.Width, b.Width) }) trtps := make([][]int, n) tptrs := make([][]int, n) for i, tru := range trunks { for j, tpu := range tops { if tru.Width < tpu.Width { trtps[i] = append(trtps[i], j) tptrs[j] = append(tptrs[j], i) } } } tplvs := make([][]int, n) lvtps := make([][]int, n*2) for i, tpu := range tops { for j, lvu := range leaves { if tpu.Width < lvu.Width { tplvs[i] = append(tplvs[i], j) lvtps[j] = append(lvtps[j], i) } } } connTrtps := make([]int, n) connTptrs := make([]int, n) connTplvs := make([][]int, n) connLvtps := make([]int, n*2) for i := range connTrtps { connTrtps[i] = -1 connTptrs[i] = -1 connTplvs[i] = []int{ -1, -1} connLvtps[i] = -1 connLvtps[i+n] = -1 } outer1: for tri, tps := range trtps { if connTrtps[tri] >= 0 { continue } for _, tpi := range tps { if connTptrs[tpi] >= 0 { continue } for i, lv1i := range tplvs[tpi] { if connLvtps[lv1i] >= 0 { continue } for _, lv2i := range tplvs[tpi][i+1:] { if connLvtps[lv2i] >= 0 { continue } connTrtps[tri] = tpi connTptrs[tpi] = tri connTplvs[tpi][0] = lv1i connTplvs[tpi][1] = lv2i connLvtps[lv1i] = tpi connLvtps[lv2i] = tpi continue outer1 } } } } height := func(tpi, lv1i, lv2i, tri int) int { return tops[tpi].Height+ leaves[lv1i].Height+ leaves[lv2i].Height+ trunks[tri].Height } bestScore := int(1e9) makeSolution := func() bool { founds := make([]int, 0, n) for tri, tpi := range connTrtps { if tpi < 0 { continue } founds = append(founds, tri) } if len(founds) < k { return false } slices.SortFunc(founds, func(tri1, tri2 int) int { tpi1 := connTrtps[tri1] lvs1 := connTplvs[tpi1] h1 := height(tpi1, lvs1[0], lvs1[1], tri1) tpi2 := connTrtps[tri2] lvs2 := connTplvs[tpi2] h2 := height(tpi2, lvs2[0], lvs2[1], tri2) return cmp.Compare(h1, h2) }) besti, bestd := 0, int(1e9) for i := 0; i+k <= len(founds); i++ { tri1 := founds[i] tri2 := founds[i+k-1] tpi1 := connTrtps[tri1] lvs1 := connTplvs[tpi1] h1 := height(tpi1, lvs1[0], lvs1[1], tri1) tpi2 := connTrtps[tri2] lvs2 := connTplvs[tpi2] h2 := height(tpi2, lvs2[0], lvs2[1], tri2) d := h2 - h1 if d < bestd { besti, bestd = i, d } } if bestd >= bestScore { return false } // println(Sprintf("update: %d", bestd)) bestScore = bestd res = make([][]int, 0, k) for _, tri := range founds[besti:] { tpi := connTrtps[tri] lvs := connTplvs[tpi] res = append(res, []int{ tops[tpi].Id, leaves[lvs[0]].Id, leaves[lvs[1]].Id, trunks[tri].Id, }) if len(res) == k { return true } } return false } // make provisional solution makeSolution() makeResult := func() { i := 0 for tpi, tri := range connTptrs { if tri < 0 { continue } lvs := connTplvs[tpi] tmp := res[i][:] tmp[0] = tops[tpi].Id tmp[1] = leaves[lvs[0]].Id tmp[2] = leaves[lvs[1]].Id tmp[3] = trunks[tri].Id i++ } } combine := func(tpi, lv1i, lv2i, tri int) { // no validatation connTptrs[tpi] = tri connTplvs[tpi][0] = lv1i connTplvs[tpi][1] = lv2i connTrtps[tri] = tpi connLvtps[lv1i] = tpi connLvtps[lv2i] = tpi } destroy := func(tpi int) { tri := connTptrs[tpi] lvs := connTplvs[tpi] connTrtps[tri] = -1 connLvtps[lvs[0]] = -1 connLvtps[lvs[1]] = -1 connTptrs[tpi] = -1 lvs[0] = -1 lvs[1] = -1 } { founds := make([]int, 0, n) for tpi, tri := range connTptrs { if tri < 0 { continue } founds = append(founds, tpi) } slices.SortFunc(founds, func(tpi1, tpi2 int) int { tri1 := connTptrs[tpi1] lvs1 := connTplvs[tpi1] h1 := height(tpi1, lvs1[0], lvs1[1], tri1) tri2 := connTptrs[tpi2] lvs2 := connTplvs[tpi2] h2 := height(tpi2, lvs2[0], lvs2[1], tri2) return cmp.Compare(h1, h2) }) besti, bestd := -1, int(1e9) for i := 0; i+k <= len(founds); i++ { tpi1 := founds[i] tpi2 := founds[i+k-1] tri1 := connTptrs[tpi1] lvs1 := connTplvs[tpi1] h1 := height(tpi1, lvs1[0], lvs1[1], tri1) tri2 := connTptrs[tpi2] lvs2 := connTplvs[tpi2] h2 := height(tpi2, lvs2[0], lvs2[1], tri2) d := h2-h1 if d < bestd { besti, bestd = i, d } } for i, tpi := range founds { if besti <= i && i < besti+k { continue } destroy(tpi) } } perms := make([][]int, n+1) for i := range perms { if i == 0 { perms[0] = []int{} } else { perms[i] = rand.Perm(i) } } get := func(i int) []int { perm := perms[i] rand.Shuffle(i, func(i, j int) { sort.IntSlice(perm).Swap(i, j) }) return perm } tphs := make([]int, n) for tpi := range tphs { tri := connTptrs[tpi] if tri < 0 { continue } lvs := connTplvs[tpi] tphs[tpi] = height(tpi, lvs[0], lvs[1], tri) } trs := make([]int, n) lvs := make([]int, n*2) for { select { case <-ch: return default: } mintpi, maxtpi := -1, -1 minh, maxh := int(1e9), 0 for tpi, tri := range connTptrs { if tri < 0 { continue } h := tphs[tpi] if h < minh { mintpi, minh = tpi, h } if h > maxh { maxtpi, maxh = tpi, h } } if maxh - minh < bestScore { bestScore = maxh - minh makeResult() } half := (maxh + minh) / 2 if half - minh < maxh - half { destroy(maxtpi) } else { destroy(mintpi) } for { select { case <-ch: return default: } besttpi, besttri, bestlv1i, bestlv2i := -1,-1,-1,-1 bestd, besth := int(1e9), 0 for tpi, tri0 := range connTptrs { if tri0 >= 0 { continue } trs = trs[:0] for _, tri := range tptrs[tpi] { if connTrtps[tri] < 0 { trs = append(trs, tri) } } if len(trs) == 0 { continue } trc := min(len(trs), 4) trps := get(len(trs))[:trc] lvs := lvs[:0] for _, lvi := range tplvs[tpi] { if connLvtps[lvi] < 0 { lvs = append(lvs, lvi) } } if len(lvs) == 0 { continue } lvc := min(len(lvs), 4) lvps := get(len(lvs))[:lvc] for _, x := range trps { tri := trs[x] for i, y := range lvps { lv1i := lvs[y] for _, z := range lvps[i+1:] { lv2i := lvs[z] h := height(tpi, lv1i, lv2i, tri) if h <= minh || maxh <= h { continue } d := half - h if d < 0 { d = -d } if d < bestd { besttpi = tpi besttri = tri bestlv1i = lv1i bestlv2i = lv2i bestd = d besth = h } } } } } if besttpi >= 0 { combine(besttpi, bestlv1i, bestlv2i, besttri) tphs[besttpi] = besth break } } } return } func main() { var ns string Scan(&ns) if ns == "LOCAL" { runLocal() return } var n, k int Sscan(ns, &n) Scan(&k) a := make([]int, n) b := make([]int, n) c := make([]int, n*2) d := make([]int, n*2) e := make([]int, n) f := make([]int, n) for _, vs := range [][]int{a,b,c,d,e,f} { for i := range vs { Scan(&vs[i]) } } ans := solve(n, k, a, b, c, d, e, f) for _, vs := range ans { Println(vs[0], vs[1], vs[2], vs[3]) } } func runLocal() { Println("RUN LOCAL") const N = 500 var seed int64 = rand.Int63() Scan(&seed) k, a, b, c, d, e, f := generate(seed, N) ans := solve(N, k, a, b, c, d, e, f) validate(N, k, a, c, e, ans) hmin, hmax := int(1e9), 0 for _, vs := range ans { h := b[vs[0]-1]+d[vs[1]-1]+d[vs[2]-1]+f[vs[3]-1] if h < hmin { hmin = h } if h > hmax { hmax = h } } Println("hmin =", hmin) Println("hmax =", hmax) Println("diff =", hmax-hmin) Println("score =", 4e4-(hmax-hmin)) Println("score*125 =", 125*(4e4-(hmax-hmin))) } func validate(n, k int, a, c, e []int, res [][]int) { if len(res) != k { panic("len != k") } usedTops := make([]bool, n+1) usedLeaves := make([]bool, n*2+1) usedTrunks := make([]bool, n+1) for i, vs := range res { if len(vs) != 4 { panic(Sprintf("[%d] %#v (len != 4)", i, vs)) } if vs[0] < 1 || n < vs[0] { panic(Sprintf("[%d] %#v (invalid id [0])", i, vs)) } if usedTops[vs[0]] { panic(Sprintf("[%d] %#v (duplicate id [0])", i, vs)) } usedTops[vs[0]] = true if vs[1] < 1 || 2*n < vs[1] { panic(Sprintf("[%d] %#v (invalid id [1])", i, vs)) } if usedLeaves[vs[1]] { panic(Sprintf("[%d] %#v (duplicate id [1])", i, vs)) } usedLeaves[vs[1]] = true if vs[2] < 1 || 2*n < vs[2] { panic(Sprintf("[%d] %#v (invalid id [2])", i, vs)) } if usedLeaves[vs[2]] { panic(Sprintf("[%d] %#v (duplicate id [2])", i, vs)) } usedLeaves[vs[2]] = true if vs[3] < 1 || n < vs[3] { panic(Sprintf("[%d] %#v (invalid id [3])", i, vs)) } if usedTrunks[vs[3]] { panic(Sprintf("[%d] %#v (duplicate id [3])", i, vs)) } usedTrunks[vs[3]] = true if a[vs[0]-1] <= e[vs[3]-1] { panic(Sprintf("[%d] %#v (a <= e)", i, vs)) } if c[vs[1]-1] <= a[vs[0]-1] { panic(Sprintf("[%d] %#v (c1 <= a)", i, vs)) } if c[vs[2]-1] <= a[vs[0]-1] { panic(Sprintf("[%d] %#v (c2 <= a)", i, vs)) } } } func generate(seed int64, n int) (k int, a,b,c,d,e,f []int) { rng := rand.New(rand.NewSource(seed)) smp := func(min, max, stddev, mean int) int { v := rng.NormFloat64()*float64(stddev)+float64(mean) return int(math.Max(float64(min),math.Min(float64(max),v))) } k = rng.Intn(101) + 300 a = make([]int, n) b = make([]int, n) c = make([]int, n*2) d = make([]int, n*2) e = make([]int, n) f = make([]int, n) for i := 0; i < k; i++ { var w [4]int for { for j := range w[:] { w[j] = smp(1, 1e4, 1600, 5000) } slices.Sort(w[:]) if len(slices.Compact(w[:])) == 4 { break } } a[i] = w[1] c[i] = w[2] c[i+n] = w[3] e[i] = w[0] } for i := k; i < n; i++ { a[i] = smp(1, 1e4, 1600, 5000) c[i] = smp(1, 1e4, 1600, 5000) c[i+n] = smp(1, 1e4, 1600, 5000) e[i] = smp(1, 1e4, 1600, 5000) } rng.Shuffle(len(a), func(i, j int) { sort.IntSlice(a).Swap(i, j) }) rng.Shuffle(len(c), func(i, j int) { sort.IntSlice(c).Swap(i, j) }) rng.Shuffle(len(e), func(i, j int) { sort.IntSlice(e).Swap(i, j) }) for i, v := range a { b[i] = smp(1, 1e4, 500, v) } for i, v := range c { d[i] = smp(1, 1e4, 500, v) } for i, v := range e { f[i] = smp(1, 1e4, 500, v) } return } func min(a, b int) int { if a < b { return a } else { return b } }