试题E:砍柴
【问题描述】
小蓝和小乔正在森林里砍柴,它们有T 根长度分别为n1,n2,…, nT 的木头。对于每个初始长度为n 的木头,小蓝和小乔准备进行交替砍柴,小蓝先出手。每次砍柴时,若当前木头长度为x ,需要砍下一截长度为p 的木头,然后换另一个人继续砍,其中2 ≤ p ≤ x 且p 必须为质数。当轮到某一方时x = 1 或x = 0 ,它就没法继续砍柴,它就输了。它们会使用最优策略进行砍柴。请对每根木头判断是小蓝赢还是小乔赢,如果小蓝赢请输出1 (数字1),如果小乔赢请输出0 (数字0)。
【输入格式】
输入的第一行包含一个正整数T,
接下来T 行,每行包含一个正整数,其中第i 的整数为ni 。
【输出格式】
输出T 行,每行包含一个整数,依次表示对于每一根木头的答案。
【样例输入】
3
1
2
6
【样例输出】
0
1
1
import math
# 筛法预处理得到范围内所有质数
def get_primes(max_val):
v = [True] * (max_val + 1)
for x in range(2, max_val + 1):
if not v[x]:
continue
for y in range(x * 2, max_val + 1, x):
v[y] = False
primes = [x for x in range(2, max_val + 1) if v[x]]
return primes
# DFS 博弈
def win(x):
if memo[x] != 0:
return memo[x] == 1
if x <= 1:
return False
# 剪枝: 倒序遍历质数集, 更快接近 DFS 基态
for i in range(bis(x), -1, -1):
if not win(x - primes[i]):
memo[x] = 1
return True
memo[x] = -1
return False
# 二分, 从质数集中查找 <= x 的最大位置
def bis(x):
l = 0
r = len(primes)
while l < r:
m = (l + r) // 2
if primes[m] <= x:
l = m + 1
else:
r = m
return l-1
T = int(input())
woods = [int(input()) for _ in range(T)]
max_wood = max(woods)
primes = get_primes(max_wood)
memo = [0] * (max_wood + 1)
for wood in woods:
result = 1 if win(wood) else 0
print(result)