結果

問題 No.5016 Worst Mayor
ユーザー ra5anchor
提出日時 2025-04-30 01:25:18
言語 PyPy3
(7.3.15)
結果
AC  
実行時間 483 ms / 2,000 ms
コード長 8,191 bytes
コンパイル時間 579 ms
コンパイル使用メモリ 82,048 KB
実行使用メモリ 102,440 KB
スコア 21,111,845,180
平均クエリ数 400.00
最終ジャッジ日時 2025-04-30 01:25:49
合計ジャッジ時間 26,208 ms
ジャッジサーバーID
(参考情報)
judge2 / judge5
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 50
権限があれば一括ダウンロードができます

ソースコード

diff #

import copy
import random
from time import perf_counter
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


class TimeKeeper:
    def __init__(self):
        self.start_time = perf_counter()
    def is_time_over(self, LIMIT):
        return (perf_counter() - self.start_time) >= LIMIT
    def time_now(self):
        return (perf_counter() - self.start_time)


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.no_more_road = False

    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 を使って収益を計算
        revenue_pre = self.daily_revenue
        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
        # if self.daily_revenue < revenue_pre and len(self.highways)>=50:
        #     self.no_more_road = True
        return

    def choose_action(self):
        if self.collaborators < 50:
            return [2]
        if self.day >= 300:
            return [3]
        cost = int(HIGHWAY_BUILD_BASE_COST / math.sqrt(self.collaborators))
        if self.money < cost:
            return [3]

        if self.no_more_road == True:
            return [3]

        # 道路建設
        road = []

        s = list(range(H-1))

        for p0 in [3, 9]:
        # for p0 in [6]:
            path = []
            r, c = 0, p0
            path.append((r, c))
            while r < H-1:
                if len(path)%2==1:
                    r += 1
                elif len(path)%4==0:
                    c -= 1
                elif len(path)%4==2:
                    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)
                edges.append((r0, c0, r1, c1))
            edges.sort(key=lambda x: abs(14-(x[0]+x[2])))
            road.extend(edges)

            path = []
            r, c = p0, 0
            path.append((r, c))
            while c < H-1:
                if len(path)%2==1:
                    c += 1
                elif len(path)%4==0:
                    r -= 1
                elif len(path)%4==2:
                    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)
                edges.append((r0, c0, r1, c1))
            edges.sort(key=lambda x: abs(14-(x[1]+x[3])))
            road.extend(edges)

        #! 順番を保ったまま重複を除去
        road = list(dict.fromkeys(road))

        # print(road, file=sys.stderr)
        max_road = 100
        rid = len(self.highways)
        # if rid >= 50:
        if rid >= len(road) or rid >= max_road:
            return [3]
        else:
            a, b, c, d = road[rid]
            return [1, a, b, c, d]


    def solve(self, tk, LIMIT):
        for day in range(self.T):
            self.day = day
            if not self.DEBUG:
                M, C = map(int, input().split())
                self.money, self.collaborators = M, C
            action = self.choose_action()
            self.actions.append(action)
            self.execute_action(action)

            # DEBUG モードで収益更新
            # if self.DEBUG and action[0] == 1:
            #     self.update_daily_revenue()
            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 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):
    tk = TimeKeeper()
    LIMIT = 0.8
    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])
    solver = Solver(N, T, citizens, DEBUG)
    ans, sc = solver.solve(tk, LIMIT)
    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)
0