提出 #72942201


ソースコード 拡げる

import sys
import time
import random
import math
from collections import deque

# --- チューニング設定 ---
TIME_LIMIT = 1.95
SA_TIME_LIMIT = 1.45    # 高速化したので時間をたっぷりとる
SA_DEPTH = 8            # ビット演算なら深さ8まで余裕でいける
BFS_LIMIT = 3500

def solve():
    start_time = time.time()
    
    # --- 1. 入力 ---
    try:
        line1 = sys.stdin.readline().split()
        if not line1: return
        N, M, K, T = map(int, line1)
        
        adj = [[] for _ in range(N)]
        degrees = [0] * N
        for _ in range(M):
            u, v = map(int, sys.stdin.readline().split())
            adj[u].append(v)
            adj[v].append(u)
            degrees[u] += 1
            degrees[v] += 1
        
        for _ in range(N):
            sys.stdin.readline()
    except ValueError:
        return

    # --- 2. Safe Core (安全圏) ---
    is_safe = [True] * N
    curr_degrees = list(degrees)
    queue = deque([i for i in range(N) if curr_degrees[i] == 1])
    
    while queue:
        u = queue.popleft()
        is_safe[u] = False
        for v in adj[u]:
            if is_safe[v]:
                curr_degrees[v] -= 1
                if curr_degrees[v] == 1:
                    queue.append(v)
    
    if sum(is_safe) == 0:
        for i in range(N):
            if degrees[i] >= 2: is_safe[i] = True

    # --- 3. 高速化前処理: パスのビットマスク用リスト ---
    # shop_paths[k] = [ (length, [node_indices...]), ... ]
    shop_paths = [[] for _ in range(K)]
    
    for start_node in range(K):
        q = deque([(start_node, -1, [])])
        cnt = 0
        while q:
            u, p, path = q.popleft()
            if path:
                # パス自体を保存
                shop_paths[start_node].append((len(path), path))
            
            if len(path) >= SA_DEPTH:
                continue
            
            for v in adj[u]:
                if v == p: continue
                if v < K: continue
                if not is_safe[v]: continue
                
                # 枝刈り: あまりに多すぎるとSAが遅くなるので制限
                if cnt > 1200: break
                
                q.append((v, u, path + [v]))
                cnt += 1

    # --- 4. 爆速焼きなまし (Bitwise SA) ---
    current_colors = [0] * N 
    # 初期解: 半分くらいRにしておく
    for i in range(K, N):
        if random.random() < 0.3: current_colors[i] = 1
            
    best_colors = list(current_colors)
    
    # スコア計算: 文字列操作を排除し、ビット演算とタプルのみで行う
    # seen = set( (length, bitmask_value) )
    def calc_score_fast(colors):
        total_score = 0
        r_count = 0
        
        # Rの数ペナルティ(工事コスト削減のため)
        # しかしPythonのsumは遅いので、差分更新したいがここでは簡易的に
        # K以降のsumをとる
        # r_count = sum(colors[K:]) * 0.5 # 係数は調整
        
        for i in range(K):
            seen = set()
            local_score = 0
            for length, path in shop_paths[i]:
                # ビットマスク生成
                val = 0
                for idx, node in enumerate(path):
                    if colors[node]:
                        val |= (1 << idx)
                
                # (長さ, 値) がユニークなら加点
                key = (length, val)
                if key not in seen:
                    seen.add(key)
                    # 長さの2乗をスコアに (長い文字列を強力に推奨)
                    local_score += length * length 
            
            total_score += local_score
        
        # Rが多いと少し減点(1個あたり0.1点減点など、コスト意識)
        # total_score -= sum(colors) * 0.1
        return total_score

    current_score = calc_score_fast(current_colors)
    best_score = current_score
    
    T0 = 200.0
    T1 = 1.0
    temp = T0
    
    sa_iter = 0
    while True:
        sa_iter += 1
        if (sa_iter & 255) == 0:
            now = time.time()
            if now - start_time > SA_TIME_LIMIT:
                break
            progress = (now - start_time) / SA_TIME_LIMIT
            temp = T0 + (T1 - T0) * progress
        
        target = random.randint(K, N - 1)
        if not is_safe[target]: continue
            
        current_colors[target] ^= 1 
        new_score = calc_score_fast(current_colors)
        
        delta = new_score - current_score
        
        if delta >= 0:
            current_score = new_score
            if current_score > best_score:
                best_score = current_score
                best_colors = list(current_colors)
        else:
            try:
                prob = math.exp(delta / temp)
            except OverflowError:
                prob = 0
            if random.random() < prob:
                current_score = new_score
            else:
                current_colors[target] ^= 1 # Revert

    # --- 5. 実行パート (Real-Cost Greedy) ---
    real_tree_flavors = [0] * N
    delivered_strings = [set() for _ in range(K)]
    
    current_pos = 0
    prev_pos = -1
    current_ice = ""
    action_queue = deque()
    
    for t_idx in range(T):
        turns_left = T - t_idx
        
        # 計画作成
        if not action_queue:
            # (pos, prev, current_string, path_history, flip_cost)
            q = deque([(current_pos, prev_pos, current_ice, [], 0)])
            visited = { (current_pos, current_ice) }
            
            candidates = []
            bfs_cnt = 0
            
            while q:
                u, p, s, path, flips = q.popleft()
                bfs_cnt += 1
                if bfs_cnt > BFS_LIMIT: break
                
                # 距離 + 工事コスト が残りターンを超えたら無意味
                current_total_cost = len(path) + flips
                if current_total_cost > turns_left: continue
                if len(path) > 16: continue # 遠すぎるのは見ない
                
                # ショップ到達
                if u < K:
                    if s != "" and s not in delivered_strings[u]:
                        # 評価関数
                        # Value: 長さの2.5乗(長いのが正義)
                        # Cost: 移動距離 + (工事回数 * 1.5) 
                        # ※工事には1ターンかかるが、リスクもあるので少し重く見る
                        score = len(s) ** 2.5
                        cost = len(path) + (flips * 1.2) + 0.1
                        efficiency = score / cost
                        
                        candidates.append((path, score, efficiency))
                    continue
                
                # 移動先列挙
                next_nodes = []
                for v in adj[u]:
                    if v == p: continue
                    if is_safe[u] and not is_safe[v]: continue
                    next_nodes.append(v)
                
                for v in next_nodes:
                    new_flips = flips
                    if v >= K:
                        # 理想の色にする必要があるか?
                        # 現在の色を取得
                        actual_color = real_tree_flavors[v]
                        # 理想の色 (best_colors) を使う前提でパスを組む
                        target_color = best_colors[v]
                        
                        # もし「今の現実」と「理想」が違うなら、工事コスト+1
                        # そして、その場所で得られる色は「理想の色」になる
                        if actual_color != target_color:
                            new_flips += 1
                        
                        flavor = 'R' if target_color == 1 else 'W'
                        next_s = s + flavor
                    else:
                        next_s = s
                    
                    if len(next_s) <= 8: # 長さ8まで許容
                        if (v, next_s) not in visited:
                            visited.add((v, next_s))
                            q.append((v, u, next_s, path + [v], new_flips))
            
            # ベストパス選択
            if candidates:
                # 常に「効率(コスパ)」最優先
                candidates.sort(key=lambda x: -x[2]) 
                best_path = candidates[0][0]

                for node in best_path:
                    action_queue.append(node)
                    # 味変予約: 現実と理想が違うなら変える
                    if node >= K and real_tree_flavors[node] != best_colors[node]:
                        action_queue.append(-1)
            else:
                # ランダム移動 (Safe優先)
                cands = [v for v in adj[current_pos] if v != prev_pos]
                safe_cands = [v for v in cands if is_safe[v]]
                if is_safe[current_pos] and safe_cands:
                    action_queue.append(random.choice(safe_cands))
                elif cands:
                    action_queue.append(random.choice(cands))
                else:
                    pass

        # --- 実行 (Safety Guard) ---
        final_action = -999
        while action_queue:
            cand = action_queue.popleft()
            if cand == -1:
                # 味変: 今の場所で、色が違うなら実行
                if current_pos < K: continue
                if real_tree_flavors[current_pos] == best_colors[current_pos]: continue 
                final_action = -1; break
            else:
                if cand == prev_pos or cand not in adj[current_pos]: continue
                final_action = cand; break
        
        if final_action == -999:
            cands = [v for v in adj[current_pos] if v != prev_pos]
            safe_cands = [v for v in cands if is_safe[v]]
            if is_safe[current_pos] and safe_cands: final_action = safe_cands[0]
            elif cands: final_action = cands[0]
            else: break 
            
        print(final_action)
        sys.stdout.flush()
        
        if final_action == -1:
            # 味を反転
            real_tree_flavors[current_pos] ^= 1
        else:
            prev_pos = current_pos
            current_pos = final_action
            if current_pos >= K:
                current_ice += ('R' if real_tree_flavors[current_pos] else 'W')
            else:
                if current_ice: delivered_strings[current_pos].add(current_ice)
                current_ice = ""

if __name__ == "__main__":
    solve()

提出情報

提出日時
問題 A - Ice Cream Collection
ユーザ glaceon1020
言語 Python (PyPy 3.11-v7.3.20)
得点 86044
コード長 11075 Byte
結果 AC
実行時間 1846 ms
メモリ 120168 KiB

ジャッジ結果

セット名 test_ALL
得点 / 配点 86044 / 1500000
結果
AC × 150
セット名 テストケース
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt
ケース名 結果 実行時間 メモリ
test_0000.txt AC 1702 ms 117892 KiB
test_0001.txt AC 1760 ms 119732 KiB
test_0002.txt AC 1687 ms 117816 KiB
test_0003.txt AC 1708 ms 118892 KiB
test_0004.txt AC 1696 ms 118480 KiB
test_0005.txt AC 1738 ms 118600 KiB
test_0006.txt AC 1664 ms 117032 KiB
test_0007.txt AC 1706 ms 117960 KiB
test_0008.txt AC 1744 ms 119176 KiB
test_0009.txt AC 1765 ms 119616 KiB
test_0010.txt AC 1719 ms 119028 KiB
test_0011.txt AC 1704 ms 117936 KiB
test_0012.txt AC 1804 ms 118460 KiB
test_0013.txt AC 1708 ms 117684 KiB
test_0014.txt AC 1724 ms 118256 KiB
test_0015.txt AC 1676 ms 117940 KiB
test_0016.txt AC 1745 ms 118736 KiB
test_0017.txt AC 1718 ms 117916 KiB
test_0018.txt AC 1759 ms 118912 KiB
test_0019.txt AC 1751 ms 119376 KiB
test_0020.txt AC 1727 ms 118436 KiB
test_0021.txt AC 1791 ms 119912 KiB
test_0022.txt AC 1711 ms 118560 KiB
test_0023.txt AC 1766 ms 118764 KiB
test_0024.txt AC 1695 ms 117500 KiB
test_0025.txt AC 1749 ms 119920 KiB
test_0026.txt AC 1695 ms 117884 KiB
test_0027.txt AC 1754 ms 118636 KiB
test_0028.txt AC 1713 ms 118556 KiB
test_0029.txt AC 1761 ms 118692 KiB
test_0030.txt AC 1730 ms 118480 KiB
test_0031.txt AC 1756 ms 119516 KiB
test_0032.txt AC 1708 ms 117840 KiB
test_0033.txt AC 1708 ms 118468 KiB
test_0034.txt AC 1783 ms 118992 KiB
test_0035.txt AC 1706 ms 118496 KiB
test_0036.txt AC 1678 ms 118052 KiB
test_0037.txt AC 1673 ms 117612 KiB
test_0038.txt AC 1779 ms 120168 KiB
test_0039.txt AC 1727 ms 118776 KiB
test_0040.txt AC 1680 ms 117272 KiB
test_0041.txt AC 1765 ms 118668 KiB
test_0042.txt AC 1691 ms 118660 KiB
test_0043.txt AC 1715 ms 118516 KiB
test_0044.txt AC 1664 ms 117264 KiB
test_0045.txt AC 1725 ms 117868 KiB
test_0046.txt AC 1706 ms 118400 KiB
test_0047.txt AC 1708 ms 118116 KiB
test_0048.txt AC 1700 ms 117960 KiB
test_0049.txt AC 1748 ms 118872 KiB
test_0050.txt AC 1674 ms 117764 KiB
test_0051.txt AC 1702 ms 118320 KiB
test_0052.txt AC 1677 ms 117568 KiB
test_0053.txt AC 1846 ms 119956 KiB
test_0054.txt AC 1717 ms 118456 KiB
test_0055.txt AC 1670 ms 118132 KiB
test_0056.txt AC 1772 ms 119384 KiB
test_0057.txt AC 1666 ms 117812 KiB
test_0058.txt AC 1785 ms 119076 KiB
test_0059.txt AC 1686 ms 117116 KiB
test_0060.txt AC 1681 ms 117188 KiB
test_0061.txt AC 1700 ms 117668 KiB
test_0062.txt AC 1716 ms 119648 KiB
test_0063.txt AC 1714 ms 118880 KiB
test_0064.txt AC 1701 ms 117684 KiB
test_0065.txt AC 1700 ms 117940 KiB
test_0066.txt AC 1708 ms 118492 KiB
test_0067.txt AC 1680 ms 118496 KiB
test_0068.txt AC 1740 ms 119148 KiB
test_0069.txt AC 1691 ms 117936 KiB
test_0070.txt AC 1695 ms 117852 KiB
test_0071.txt AC 1719 ms 118340 KiB
test_0072.txt AC 1694 ms 117420 KiB
test_0073.txt AC 1663 ms 117672 KiB
test_0074.txt AC 1728 ms 118644 KiB
test_0075.txt AC 1787 ms 118244 KiB
test_0076.txt AC 1666 ms 118032 KiB
test_0077.txt AC 1708 ms 117672 KiB
test_0078.txt AC 1732 ms 118512 KiB
test_0079.txt AC 1721 ms 118388 KiB
test_0080.txt AC 1765 ms 119144 KiB
test_0081.txt AC 1724 ms 118564 KiB
test_0082.txt AC 1804 ms 119104 KiB
test_0083.txt AC 1700 ms 117864 KiB
test_0084.txt AC 1716 ms 118348 KiB
test_0085.txt AC 1736 ms 118484 KiB
test_0086.txt AC 1702 ms 118468 KiB
test_0087.txt AC 1714 ms 118376 KiB
test_0088.txt AC 1751 ms 118692 KiB
test_0089.txt AC 1743 ms 119020 KiB
test_0090.txt AC 1771 ms 118844 KiB
test_0091.txt AC 1703 ms 117716 KiB
test_0092.txt AC 1765 ms 118896 KiB
test_0093.txt AC 1699 ms 117848 KiB
test_0094.txt AC 1696 ms 118704 KiB
test_0095.txt AC 1734 ms 119000 KiB
test_0096.txt AC 1686 ms 117992 KiB
test_0097.txt AC 1730 ms 118408 KiB
test_0098.txt AC 1688 ms 117676 KiB
test_0099.txt AC 1679 ms 118316 KiB
test_0100.txt AC 1685 ms 117528 KiB
test_0101.txt AC 1738 ms 118948 KiB
test_0102.txt AC 1702 ms 118088 KiB
test_0103.txt AC 1720 ms 118972 KiB
test_0104.txt AC 1714 ms 118272 KiB
test_0105.txt AC 1756 ms 118756 KiB
test_0106.txt AC 1739 ms 118788 KiB
test_0107.txt AC 1805 ms 119584 KiB
test_0108.txt AC 1725 ms 118464 KiB
test_0109.txt AC 1694 ms 118100 KiB
test_0110.txt AC 1723 ms 118464 KiB
test_0111.txt AC 1731 ms 119248 KiB
test_0112.txt AC 1706 ms 117988 KiB
test_0113.txt AC 1709 ms 118916 KiB
test_0114.txt AC 1797 ms 118824 KiB
test_0115.txt AC 1674 ms 117548 KiB
test_0116.txt AC 1712 ms 118516 KiB
test_0117.txt AC 1753 ms 118892 KiB
test_0118.txt AC 1704 ms 118004 KiB
test_0119.txt AC 1728 ms 118028 KiB
test_0120.txt AC 1782 ms 119024 KiB
test_0121.txt AC 1727 ms 119496 KiB
test_0122.txt AC 1747 ms 119020 KiB
test_0123.txt AC 1675 ms 118388 KiB
test_0124.txt AC 1800 ms 119396 KiB
test_0125.txt AC 1698 ms 119556 KiB
test_0126.txt AC 1712 ms 118888 KiB
test_0127.txt AC 1732 ms 117812 KiB
test_0128.txt AC 1696 ms 117332 KiB
test_0129.txt AC 1691 ms 117988 KiB
test_0130.txt AC 1754 ms 119076 KiB
test_0131.txt AC 1687 ms 118208 KiB
test_0132.txt AC 1729 ms 117640 KiB
test_0133.txt AC 1728 ms 118356 KiB
test_0134.txt AC 1726 ms 118384 KiB
test_0135.txt AC 1757 ms 119408 KiB
test_0136.txt AC 1756 ms 119708 KiB
test_0137.txt AC 1701 ms 118048 KiB
test_0138.txt AC 1666 ms 117976 KiB
test_0139.txt AC 1718 ms 118604 KiB
test_0140.txt AC 1785 ms 118712 KiB
test_0141.txt AC 1738 ms 118644 KiB
test_0142.txt AC 1714 ms 118144 KiB
test_0143.txt AC 1736 ms 119324 KiB
test_0144.txt AC 1712 ms 118576 KiB
test_0145.txt AC 1768 ms 118868 KiB
test_0146.txt AC 1658 ms 117748 KiB
test_0147.txt AC 1697 ms 117800 KiB
test_0148.txt AC 1730 ms 118736 KiB
test_0149.txt AC 1794 ms 118988 KiB