LeetCode1927 求和游戏——挖掘性质的博弈论

先手=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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值