結果
問題 |
No.5016 Worst Mayor
|
ユーザー |
|
提出日時 | 2025-05-11 03:26:30 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 1,295 ms / 2,000 ms |
コード長 | 11,035 bytes |
コンパイル時間 | 574 ms |
コンパイル使用メモリ | 82,848 KB |
実行使用メモリ | 110,984 KB |
スコア | 26,952,575,300 |
平均クエリ数 | 400.00 |
最終ジャッジ日時 | 2025-05-11 03:27:39 |
合計ジャッジ時間 | 65,907 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 50 |
ソースコード
import argparse import sys import math # --- Constants --- H = 14 INITIAL_MONEY = 10**6 INITIAL_COLLABORATORS = 1 NORMAL_COST = 1.0 HIGHWAY_COST = 0.223 HIGHWAY_REVENUE = 30 FUNDRAISE_AMOUNT = 50000 HIGHWAY_BUILD_BASE_COST = 10**7 def floyd_warshall_init(H, normal_cost): V = H * H INF = float('inf') # distance and highway-count matrices dist = [[INF] * V for _ in range(V)] hw_count = [[0] * V for _ in range(V)] # self-distance for u in range(V): dist[u][u] = 0.0 # grid adjacency for r in range(H): for c in range(H): u = r * H + c for dr, dc in [(0,1),(0,-1),(1,0),(-1,0)]: nr, nc = r + dr, c + dc if 0 <= nr < H and 0 <= nc < H: v = nr * H + nc dist[u][v] = normal_cost # initial APSP for k in range(V): for i in range(V): dik = dist[i][k] hik = hw_count[i][k] for j in range(V): nd = dik + dist[k][j] if nd < dist[i][j]: dist[i][j] = nd hw_count[i][j] = hik + hw_count[k][j] return dist, hw_count INIT_DIST, INIT_HW = floyd_warshall_init(H, NORMAL_COST) class Solver: def __init__(self, N, T, citizens, DEBUG): self.N = N self.T = T self.citizens = citizens self.DEBUG = DEBUG # --- 状態変数 --- self.money = INITIAL_MONEY self.collaborators = INITIAL_COLLABORATORS self.highways = set() self.day = 0 self.actions = [] self.daily_revenue = 0 # APSP 用行列の初期化 self.V = H * H # self.dist, self.hw_count = floyd_warshall_init(H, NORMAL_COST) self.dist = [row[:] for row in INIT_DIST] self.hw_count = [row[:] for row in INIT_HW] def update_apsp_edge(self, u, v): # 新しい高速道路エッジ (u<->v) を反映 V = self.V w = HIGHWAY_COST # 直接距離更新 self.dist[u][v] = w self.dist[v][u] = w self.hw_count[u][v] = 1 self.hw_count[v][u] = 1 # 差分更新 for i in range(V): di_u = self.dist[i][u] hi_u = self.hw_count[i][u] di_v = self.dist[i][v] hi_v = self.hw_count[i][v] for j in range(V): # i -> u -> v -> j nd = di_u + w + self.dist[v][j] nh = hi_u + 1 + self.hw_count[v][j] if nd < self.dist[i][j]: self.dist[i][j] = nd self.hw_count[i][j] = nh # i -> v -> u -> j nd2 = di_v + w + self.dist[u][j] nh2 = hi_v + 1 + self.hw_count[u][j] if nd2 < self.dist[i][j]: self.dist[i][j] = nd2 self.hw_count[i][j] = nh2 def execute_action(self, action): t = action[0] if t == 1: # 道路建設 r1, c1, r2, c2 = action[1:] cost = int(HIGHWAY_BUILD_BASE_COST / math.sqrt(self.collaborators)) if self.money >= cost: self.money -= cost n1 = r1 * H + c1 n2 = r2 * H + c2 edge = tuple(sorted((n1, n2))) self.highways.add(edge) # APSP の差分更新 self.update_apsp_edge(n1, n2) else: print(f"ERROR no money: {action=}") exit() elif t == 2: # 協力者集め self.collaborators += 1 elif t == 3: # 資金集め self.money += FUNDRAISE_AMOUNT return def update_daily_revenue(self): # APSP の hw_count を使って収益を計算 total = 0 for a, b, c, d in self.citizens: s = a * H + b t = c * H + d total += self.hw_count[s][t] self.daily_revenue = 2 * HIGHWAY_REVENUE * total return # ジグザグのパス(縦方向)をつくる def gen_edges_v(self, p0, type): path = [] r, c = 0, p0 path.append((r, c)) for i in range(2*H-1): if i%4==0: c += 1 elif i%4==2: c -= 1 else: r += 1 path.append((r, c)) edges = [] for i in range(len(path)-1): r0, c0 = path[i] r1, c1 = path[i+1] if (r0, c0) > (r1, c1): (r0, c0), (r1, c1) = (r1, c1), (r0, c0) if type == 1: if c0 == c1 and c0 == p0: c0 += 1 c1 += 1 elif c0 == c1 and c0 != p0: c0 -= 1 c1 -= 1 edges.append((r0, c0, r1, c1)) edges.sort(key=lambda x: abs(13-(x[0]+x[2]))) return edges # ジグザグのパス(横方向)をつくる def gen_edges_h(self, p0, type): path = [] r, c = p0, 0 path.append((r, c)) for i in range(2*H-1): if i%4==0: r += 1 elif i%4==2: r -= 1 else: c += 1 path.append((r, c)) edges = [] for i in range(len(path)-1): r0, c0 = path[i] r1, c1 = path[i+1] if (r0, c0) > (r1, c1): (r0, c0), (r1, c1) = (r1, c1), (r0, c0) if type == 1: if r0 == r1 and r0 == p0: r0 += 1 r1 += 1 elif r0 == r1 and r0 != p0: r0 -= 1 r1 -= 1 edges.append((r0, c0, r1, c1)) edges.sort(key=lambda x: abs(13-(x[1]+x[3]))) return edges def choose_action(self, types, v, pos1, pos2, pos3): if self.collaborators < 60: return [2] if self.collaborators < 75 and len(self.highways) == 1: return [2] if self.collaborators < 85 and len(self.highways) == 2: return [2] if self.day >= 300: return [3] cost = int(HIGHWAY_BUILD_BASE_COST / math.sqrt(self.collaborators)) if self.money < cost: return [3] # 道路建設 road = [] if types[0] == 0: edges0 = self.gen_edges_v(pos1, types[2]) road.extend(edges0[:v]) if types[1] == 0: edges1 = self.gen_edges_h(pos2, types[3]) road.extend(edges1) edges2 = self.gen_edges_h(pos3, types[4]) road.extend(edges2) elif types[1] == 1: edges1 = self.gen_edges_h(pos3, types[3]) road.extend(edges1) edges2 = self.gen_edges_h(pos2, types[4]) road.extend(edges2) road.extend(edges0[v:]) elif types[0] == 1: edges0 = self.gen_edges_h(pos1, types[2]) road.extend(edges0[:v]) if types[1] == 0: edges1 = self.gen_edges_v(pos2, types[3]) road.extend(edges1) edges2 = self.gen_edges_v(pos3, types[4]) road.extend(edges2) elif types[1] == 1: edges1 = self.gen_edges_v(pos3, types[3]) road.extend(edges1) edges2 = self.gen_edges_v(pos2, types[4]) road.extend(edges2) road.extend(edges0[v:]) # 順番を保ったまま重複を除去 road = list(dict.fromkeys(road)) rid = len(self.highways) if rid >= len(road): return [3] else: a, b, c, d = road[rid] return [1, a, b, c, d] def solve(self, types, v, pos1, pos2, pos3, simu): for day in range(self.T): self.day = day if self.DEBUG==False and simu==False: M, C = map(int, input().split()) self.money, self.collaborators = M, C action = self.choose_action(types, v, pos1, pos2, pos3) self.actions.append(action) self.execute_action(action) # 収益更新 self.update_daily_revenue() # 収益反映 self.money += self.daily_revenue # デバッグ出力 # print(f"day={day} action={action} money={self.money} cols={self.collaborators} highways={len(self.highways)} revenue={self.daily_revenue}", file=sys.stderr) # 出力 if simu==False: if action[0] == 1: a, b, c, d = action[1:] print(1, a+1, b+1, c+1, d+1) else: print(action[0]) return self.actions, self.money def main(DEBUG): print(f"=================", file=sys.stderr) N, T = map(int, input().split()) citizens = [] for _ in range(N): a, b, c, d = map(int, input().split()) citizens.append([a-1, b-1, c-1, d-1]) # パラメータ探索 ntype = 5 types = [0] * ntype v = 28 best_sc = 0 best_types = types[:] pos1, pos2, pos3 = 6, 2, 10 def eval_config(t, vv, p1, p2, p3): solver = Solver(N, T, citizens, DEBUG) _, sc = solver.solve(t, vv, p1, p2, p3, simu=True) print(f"types={t} v={vv} pos=({p1},{p2},{p3}) sc={sc}", file=sys.stderr) return sc # 道路配置(道路1の縦横) best_sc = eval_config(types, v, pos1, pos2, pos3) for idx in range(1): trial = best_types[:] trial[idx] ^= 1 sc = eval_config(trial, v, pos1, pos2, pos3) if sc > best_sc: best_sc, best_types = sc, trial # pos1 道路1の位置 for p in (5, 7): sc = eval_config(best_types, v, p, pos2, pos3) if sc > best_sc: best_sc, pos1 = sc, p # pos2 道路2の位置 sc = eval_config(best_types, v, pos1, 1, pos3) if sc > best_sc: best_sc, pos2 = sc, 1 # pos3 道路3の位置 sc = eval_config(best_types, v, pos1, pos2, 11) if sc > best_sc: best_sc, pos3 = sc, 11 # 道路2,3の順番、微妙な配置変え for idx in range(1, ntype): trial = best_types[:] trial[idx] ^= 1 sc = eval_config(trial, v, pos1, pos2, pos3) if sc > best_sc: best_sc, best_types = sc, trial # 道路1の後半を後から設置 for vv in (20,): sc = eval_config(best_types, vv, pos1, pos2, pos3) if sc > best_sc: best_sc, v = sc, vv solver = Solver(N, T, citizens, DEBUG) _, sc = solver.solve(best_types, v, pos1, pos2, pos3, simu=False) # 本番 print("SC", sc, file=sys.stderr) if __name__ == '__main__': parser = argparse.ArgumentParser(description='Debug mode') parser.add_argument('--debug', action='store_true', help='Enable debug mode') args = parser.parse_args() main(args.debug)