先手=Alice,后手=Bob
传送门
这题太难了QAQ
这题有很多种分类讨论的方法,其中一种是按’?‘的个数分类。首先,如果’?'共有奇数个,先手必赢。因为最后一步是轮到先手,使得左侧==右侧的填法≤1个,但先手的填法有10个,任选一个使得左侧≠右侧即可。
现在’?'共有偶数个。设问号多的那侧有q1
个,对应的数字和为s1
。于是有q2,s2
。
-
q1==q2
。若s1==s2
,后手赢。因为先手在某侧填了x,后手总是能在另一侧填x。否则先手赢。因为先手总是能选择在数字和大的那一侧填9,使得后手不能追上。 -
q1>q2
。考虑后手总是有一个策略:和先手在不同侧填相同的数字。如果后手选择这一策略,则q1这侧剩q1-q2
个’?’。此时先手有增大和减小两种策略。后手唯一的选择是对抗。因此总是每消耗2个’?’,数字增大9。因此,现在设(q1-q2)*9/2+s1 < s2
,则先手可选择减小策略,即每次都填0,后手即使选9也无能为力。再看(q1-q2)*9/2+s1 > s2
,则先手可选择增大策略,即每次都填9,后手即使选0也无能为力。若刚好相等,则先手填x,后手就填9-x
,此时后手必胜。综上,后手选择以上策略时,只有(q1-q2)*9/2+s1 == s2
时才能赢。这个式子
(q1-q2)*9/2+s1 == s2
看上去很关键。在后手选择消去策略必败时,能否也得到类似的结果?若(q1-q2)*9/2+s1 < s2
,先手每次都填0,则后手为了对抗,只能在同侧填9,左侧式子就变成(q1-q2-2)*9/2+s1+9
,和原先没有差别。同理,先手每次都填9时,后手只能在同侧填0,左侧式子也不变。综上,无论后手选择与不选择消去策略,赢家都只与式子(q1-q2)*9/2+s1 == s2
有关。
把分类讨论的结果综合一下,就是:
q1+q2
为奇数,先手赢。- 否则
(q1-q2)*9/2+s1 == s2
等价于后手赢。
一个实现上的小技巧:因为q1、q2所在的侧角色交换,式子不变,所以直接令左侧的变量为q1,右侧的变量为q2即可,避免了swap操作。
class Solution:
def sumGame(self, a: str) -> bool:
n = len(a)
s1,s2,q1,q2 = 0,0,0,0
for i in range(n):
if a[i] == '?':
if i < n//2: q1 += 1
else: q2 += 1
else:
if i < n//2: s1 += ord(a[i])-ord('0')
else: s2 += ord(a[i])-ord('0')
if (q1+q2)%2: return True
return (s1-s2)+9*(q1-q2)//2 != 0