結果
| 問題 |
No.5001 排他的論理和でランニング
|
| ユーザー |
|
| 提出日時 | 2025-04-19 14:26:51 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
AC
|
| 実行時間 | 1,288 ms / 1,500 ms |
| コード長 | 4,734 bytes |
| コンパイル時間 | 510 ms |
| コンパイル使用メモリ | 82,248 KB |
| 実行使用メモリ | 102,040 KB |
| スコア | 52,270,145 |
| 最終ジャッジ日時 | 2025-04-19 14:27:06 |
| 合計ジャッジ時間 | 13,296 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 50 |
ソースコード
import copy
import random
from time import perf_counter
import argparse
import sys
import math
random.seed(0)
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 XorSet:
def __init__(self, initial):
# リスト+辞書で要素集合を管理し、
# 定数時間でランダム選択・追加・削除・XOR 更新を行う
self.data = list(initial)
self.pos = {v:i for i,v in enumerate(self.data)}
self.current_xor = 0
for v in self.data:
self.current_xor ^= v
def __len__(self):
return len(self.data)
def random_element(self):
idx = random.randrange(len(self.data))
return self.data[idx]
def remove(self, v):
idx = self.pos[v]
last = self.data[-1]
# スワップして末尾を pop
self.data[idx] = last
self.pos[last] = idx
self.data.pop()
del self.pos[v]
# XOR 更新
self.current_xor ^= v
def add(self, v):
self.pos[v] = len(self.data)
self.data.append(v)
# XOR 更新
self.current_xor ^= v
def hill_climbing_xor(values, M, tk, LIMIT):
# 初期分割
random.shuffle(values)
Sa = XorSet(values[:M])
Sb = XorSet(values[M:])
best_xor = Sa.current_xor
loop = 0
while True:
loop += 1
if loop%100==0 and tk.is_time_over(LIMIT):
break
# 近傍:A から a_val, Sb から b_val をランダムに選んで交換を試す
a_val = Sa.random_element()
b_val = Sb.random_element()
# 交換後の Sa の XOR を定数時間で計算
new_xor = Sa.current_xor ^ a_val ^ b_val
# 改善があれば実際にスワップ
if new_xor > Sa.current_xor:
Sa.remove(a_val)
Sb.remove(b_val)
Sa.add(b_val)
Sb.add(a_val)
best_xor = new_xor
print(f"best: {loop=} {best_xor=}", file=sys.stderr)
return Sa, Sb, best_xor
def hill_climbing_xor2(values, M, K, xor_init, tk, LIMIT, perfect=2**20-1):
# K個少ない
M = M - K
# 初期分割
random.shuffle(values)
Sa = XorSet(values[:M])
Sb = XorSet(values[M:])
Sa.current_xor ^= xor_init
best_xor = Sa.current_xor
loop = 0
while True:
loop += 1
if loop%100==0 and tk.is_time_over(LIMIT):
break
if loop%100==0 and best_xor >= perfect - (2**K-1):
break
# 近傍:A から a_val, Sb から b_val をランダムに選んで交換を試す
a_val = Sa.random_element()
b_val = Sb.random_element()
# 交換後の Sa の XOR を定数時間で計算
new_xor = Sa.current_xor ^ a_val ^ b_val
# 改善があれば実際にスワップ
if new_xor > Sa.current_xor:
Sa.remove(a_val)
Sb.remove(b_val)
Sa.add(b_val)
Sb.add(a_val)
best_xor = new_xor
print(f"best: {loop=} {best_xor=}", file=sys.stderr)
return Sa, Sb, best_xor
###########################################
def main(DEBUG):
tk = TimeKeeper()
LIMIT = 1.2
N, M = map(int, input().split())
A = list(map(int, input().split()))
# 5 <= N <= 10**5
# 1 <= M <= N
# 1 <= Ai <= 10**6
# Ai != Aj
# print(M, file=sys.stderr)
# exit()
A.sort()
La = []
Lb = []
for k in range(10):
K = k
found = False
for i in range(len(A)-1):
a1 = A[i+1]
a0 = A[i]
if a1 - a0 == 2**k:
# print(k, a0, a1, file=sys.stderr)
La.append(a0)
Lb.append(a1)
A.remove(a0)
A.remove(a1)
found = True
break
if found == False:
break
xor_init = 0
for i in range(K):
if La[i] != -1:
xor_init ^= La[i]
Sa, Sb, best = hill_climbing_xor2(A, M, K, xor_init, tk, LIMIT)
ans = Sa.data[:]
for k in range(K):
if (best>>k) & 1 == 1:
ans.append(La[k])
else:
ans.append(Lb[k])
best += (1<<k)
# print(*Sa.data)
print(*ans)
print("SC", best, file=sys.stderr)
return
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)