蓝桥杯A组——Python(10.01)Day5

蓝桥杯A组——Python(10.01)Day5

试题I:异或数列:

   A和B正在玩一个异或数列的游戏。初始时,A和B分别有一个整数a和b,初始值均为0。
   有一个给定的长度为n的公共数列X1,X2,···,Xn。A和B轮流操作,A先手,每步可以在以下两种选项中选一种:

选项1:从数列中选一个Xi;给A的数异或上,或者说令a变为a^Xi(其中表示按位异或——参加运算的二进制数位值相同为0,否则为1。)
选项2:从数列中选一个Xi;给B的数异或上,或者说令b变为b^Xi

   每个数Xi,都只能用一次,当所有Xi,均被使用后 (n轮后)游戏结束。游戏结束时,拥有的数比较大的一方获胜,如果双方数值相同,即为平手。
现在双方都足够聪明,都采用最优策略,请问谁能获胜?(保证输入的数小于20位二进制)

#问题的关键在于找到A,B获胜条件,这题就简单了

#以下函数实现判断输入一个数组判断谁胜
def solve(a):
    for i in range(20,-1,-1):
        cnt = 0
        for j in range(1,len(a)):
            if (a[j]>>i)&1:     #移位判断是否为1
                cnt += 1
        if cnt%2==0:
            continue
        if cnt==1 or a[0]%2==1:
            print('A胜')
            return
        else:
            print('B胜')
            return
    print('平')
    return
a = list(map(int,input('输入若干个数字用逗号分开:').split(',')))
solve(a)

#数理分析后发现A,B获胜与数组的奇偶性相关:
   如果二进制最高位的数量cnt为奇数时,是一定可以直接分出胜负的,当数的个数为偶数时先手必输,为奇数时先手必胜。
   特例cnt为1时先手必胜。如果当前最高位比较不出来,则看下一位。

~~ ~~

试题J:括号序列:
   给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。
   两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。
   例如,对于括号序列((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()、()(())、(())()、(())()和((()))。

#重点在于理解合法性检验,先看代码

def solve(s):
    f = [[0]*(n+5) for i in range(n+5)]
    f[0][0]=1
    for i in range(1,n+1):
        if s[i]=='(':
            for j in range(1,n+1):
                f[i][j] = f[i-1][j-1]
        else:
            f[i][0] = (f[i-1][0]+f[i-1][1])
            for j in range(1,n+1):
                f[i][j] = (f[i][j-1] + f[i-1][j+1])
    for i in range(n+1):
        if f[n][i]:
            return f[n][i]

s = list(input('请输入若干个括号:'))
ns1 = ['0'] + s
n = len(ns1)-1

l = solve(ns1)
s.reverse()
ns2 = ['0'] + s
for i in range(1,n+1):
    if ns2[i]=='(':
        ns2[i]=')'
    else:
        ns2[i]='('
#逆向补全
r = solve(ns2)
print(l*r)

下面引用别的大神的解释,这篇的题目也是在上面找的

几个需要清楚的问题:

①关于括号序列合法性:对于一段括号序列,从左往右起,一个字符一个字符的往前看,对于每一段小的括号序列 –‘(’– 数量 大于等于
–‘)’– 数量,那么整个括号序列就合法。

    ②关于 –‘(’– 和 –’)’– 的添加可以分开来讨论:括号是被添加到原序列的括号与括号之间的空隙里的,假如左括号和右括号加入的是不同的空隙,那么它们必然是互不影响的。如果加入的是同一个空隙,那么右括号的添加必然在左括号之前,否则括号配对,添加无意义,不存在顺序的影响,那么也是互不影响的,所以我们将其的添加分开讨论。

    ③上面第二点清楚了之后,如何利用其解决问题:可以分开讨论之后,我们可以判断在原括号序列添加左括号使之变得合法,然后变换原括号序列(先将括号序列逆序,再将左括号变成右括号,右括号变成左括号),这样调整之后我们在变换后的括号序列中添加左括号使之变得合法(相当于在原括号序列添加右括号)。

下面是举例解释:

    通常我们只需要添加一种括号就能使整个括号序列合法。
    例如:
    原括号序列:((() 左括号数量大于等于右括号数量,合法,不用添加
    变换后序列:())) 左括号数量小于右括号数量,不合法,需要添加
    但也有特殊情况,需要两种括号都加
    原括号序列:) ) ( ( 乍一看好像相等,理解了第一点就知道此序列不合法,需要添加。
    变换后序列:) ) ( ( 和原括号序列一样,不合法,需要添加。
    这样一来我们的问题变成了在括号序列中添加左括号使合法的问题,所以每碰到一个右括号,我们就可以在其前边添加左括号,从刚好合法(左右括号相等)到更多的左括号(上限是括号序列长度)。

    ④dp数组的含义:之前看题解都写的一样,但是那样想我感觉始终有些问题想不明白。 自己想了一种含义(其实和原含义差不多,但是更好理解了): dp[i][j]是指前i个括号字符之前 添加不知道多少个(可以是0个) –’(’–

使这前i个括号字符合法(合法的含义又是 –’(’– 比 –’)’– 多或者相等,所以j从0开始) 的种数。
可能有点拗口…去掉括号注释来看就是:前i个括号字符之前添加不知道多少个左括号使前i个括号字符合法的种数。
也就是说加多少个我们是不管的,我们只考虑添加后的结果中左括号比右括号多多少个。而j是下标所以必定大于等于0,于是如果dp[i][j]这个状态是可以存在的那么这个值一定不是0,也就是不可能是0种。

    ⑤递推公式:
    遇到 –‘(’– :我们只考虑在 –‘)’– 前添加 –‘(’– 使这个右括号之前的括号序列合法。遇到左括号的时候,证明在这个左括号之前的括号序列已经被判断过如何使其合法了,那么加上这个左括号依然合法,所以我们不需要管这个左括号。也就是在他前面的括号序列添加左括号使其合法的种数等于加上这个左括号之后这个序列需要添加的左括号种数。
                                                                  dp[i][j]=dp[i-1][j-1];

    遇到 –‘)’– :如果这个加上这个右括号的序列本身合法,那么我们仅需添加0个左括号就能使其合法,如果不合法就需要添加刚好使得其合法的左括号甚至可以更多。
                                    dp[i][j] = dp[i-1][0] + dp[i-1][1] + … + dp[i-1][j] + dp[i-1][j+1]

————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/w2563216521/article/details/133757928

——————————————————————————————————

第一道题很有意思,第二题合法性的理解是个困扰点

已经5天,坚持。今天国庆祝祖国生日快乐,我也要出去玩了,
过几天回来继续奋进,加油!

Day5——end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值