結果

問題 No.3400 Nana's Plus Permutation Game (7 + 7) ÷ 7
コンテスト
ユーザー Sinonen
提出日時 2025-11-25 02:39:26
言語 PyPy3
(7.3.15)
結果
WA  
実行時間 -
コード長 6,897 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 161 ms
コンパイル使用メモリ 82,168 KB
実行使用メモリ 99,348 KB
平均クエリ数 6517.30
最終ジャッジ日時 2025-12-06 23:35:17
合計ジャッジ時間 46,719 ms
ジャッジサーバーID
(参考情報)
judge4 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other WA * 77
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

import sys
import random

# Increase recursion depth just in case
sys.setrecursionlimit(20000)

# Fast I/O
input = sys.stdin.readline
write = sys.stdout.write
flush = sys.stdout.flush

def solve():
    # Read N
    try:
        line = input()
        while line and not line.strip():
            line = input()
        if not line:
            return
        N = int(line.strip())
    except ValueError:
        return

    # Cache for queries to avoid duplicates and adhere to limits
    memo = {}

    def query(i, j):
        if i == j: return -1
        if i > j: i, j = j, i
        if (i, j) in memo: return memo[(i, j)]
        
        write(f"1 {i} {j}\n")
        flush()
        
        try:
            res_str = input().strip()
            if not res_str: res = -1
            else: res = int(res_str)
        except ValueError:
            res = -1
            
        memo[(i, j)] = res
        return res

    def answer(p_list):
        write(f"2 {' '.join(map(str, p_list))}\n")
        flush()

    indices = list(range(1, N + 1))

    # =======================================================
    # Phase 1: Search for the BEST Pivot (Smallest Value)
    # =======================================================
    # Strategy: Test multiple candidates. The one that successfully sums 
    # with the most random partners is likely a small number.
    # Small pivot -> Small v -> Few heads -> Fast Phase 3 -> AC.
    
    best_p = -1
    max_success_count = -1
    
    # 1. Select candidates
    # If N is small, check all. If large, check random subset.
    sample_size = min(N, 45)
    candidates = random.sample(indices, sample_size)
    
    # 2. Test each candidate
    check_limit = 5 
    if N <= 10: check_limit = N - 1
    
    for c in candidates:
        success_count = 0
        
        # Pick random partners
        partners = []
        # Safety for very small N (avoid infinite loop)
        available = [x for x in indices if x != c]
        if len(available) <= check_limit:
            partners = available
        else:
            partners = random.sample(available, check_limit)
        
        for partner in partners:
            res = query(c, partner)
            if res != -1:
                success_count += 1
        
        if success_count > max_success_count:
            max_success_count = success_count
            best_p = c
            # Optimization: If perfect score, likely 1 or 2. Stop early.
            if success_count == check_limit:
                break
    
    p = best_p
    # Fallback (should theoretically not be needed)
    if p == -1: p = indices[0]

    # =======================================================
    # Phase 2: Build Graph (Decompose into Chains)
    # =======================================================
    adj = {}
    in_degree = [0] * (N + 1)
    
    targets = [x for x in indices if x != p]
    
    for i in targets:
        res = query(p, i)
        if res != -1:
            adj[i] = res
            in_degree[res] += 1
            
    # Heads are nodes with in-degree 0
    heads = [i for i in indices if in_degree[i] == 0]
    v = len(heads) 
    head_set = set(heads)

    # =======================================================
    # Phase 3: Identify Head Values
    # =======================================================
    head_val = {}

    if v == 1:
        head_val[heads[0]] = 1
    else:
        # Step 3-1: Identify '1' via chain length
        chain_len = {}
        max_len = -1
        
        for h in heads:
            curr = h
            length = 0
            while curr in adj:
                curr = adj[curr]
                length += 1
            l = length + 1
            chain_len[h] = l
            if l > max_len:
                max_len = l
        
        candidates_for_one = [h for h in heads if chain_len[h] == max_len]
        
        one_node = -1
        
        if len(candidates_for_one) == 1:
            one_node = candidates_for_one[0]
        else:
            # Tie-breaker: '1' connects to the most other heads
            best_score = -1
            
            # Limit checks to save queries if v happened to be large (fallback)
            limit_checks = len(candidates_for_one)
            if limit_checks > 40: limit_checks = 40
            
            subset = candidates_for_one[:limit_checks]
            
            for h in subset:
                score = 0
                test_targets = heads
                if len(heads) > 15:
                    test_targets = random.sample(heads, 15)
                
                for t in test_targets:
                    if h == t: continue
                    res = query(h, t)
                    if res in head_set:
                        score += 1
                
                if score > best_score:
                    best_score = score
                    one_node = h

        head_val[one_node] = 1
        
        # Step 3-2: Identify 2..v using 1+x = x+1
        remaining = set(heads)
        if one_node in remaining:
            remaining.remove(one_node)
            
        succ_adj = {}
        succ_in_degree = {h: 0 for h in remaining}
        
        list_remaining = list(remaining)
        for h in list_remaining:
            res = query(one_node, h)
            # If res is a head, it means val(h)+1 = val(res)
            # If val(h)=v, then val(res)=v+1 (not a head), so filtered out.
            if res in remaining:
                succ_adj[h] = res
                succ_in_degree[res] += 1

        # The node with in-degree 0 is the start (value 2)
        curr = -1
        for h in remaining:
            if succ_in_degree[h] == 0:
                curr = h
                break
        
        # Safe fallback
        if curr == -1 and remaining:
            curr = list(remaining)[0]
            
        val = 2
        while True:
            head_val[curr] = val
            if curr in succ_adj:
                curr = succ_adj[curr]
                val += 1
            else:
                break
            if val > v: break

    # =======================================================
    # Phase 4: Reconstruct P
    # =======================================================
    P_res = [0] * N
    
    for h in heads:
        if h not in head_val: continue
        
        val_start = head_val[h]
        curr = h
        current_v = val_start
        
        while True:
            if 0 <= curr - 1 < N:
                P_res[curr - 1] = current_v
            
            if curr in adj:
                curr = adj[curr]
                current_v += v
            else:
                break
                
    answer(P_res)

# Main Execution
line = input()
if line:
    try:
        T_cases = int(line.strip())
        for _ in range(T_cases):
            solve()
    except ValueError:
        pass
0