【蓝桥刷题】备战国赛——异或三角

文章介绍了2021年蓝桥杯国赛中的一道关于异或三角的题目,主要涉及数位DP和DFS的解题方法。题目要求找到满足特定异或关系和能构成三角形的三个整数。解题策略包括利用异或运算的性质,通过深度优先搜索(DFS)对二进制数位进行遍历,并使用动态规划(DP)进行优化,以提高搜索效率。
摘要由CSDN通过智能技术生成

蓝桥杯2021国赛真题——异或三角



🚀 每日一题,冲刺国赛 🚀

在这里插入图片描述



题目导航:

异或三角

在这里插入图片描述


🎇思路:数位 d p dp dp + d f s dfs dfs + 思维

🔱思路分析:

数理基础:

按位异或:一种逻辑运算符,用于比较两个二进制数中每个位的状态,如果两个数的状态不同,则结果为 1 1 1;反之,结果为 0 0 0,其在 p y t h o n python python 语法中表现为 a     ˆ   b a\ \^\ \ b a  ˆ b,在本题中表现为 a ⊕ b a⊕b ab

如:10 ^ 01 = 111100 ^ 1010 = 0110


按位异或的性质:

  1. 恒等律: a     ˆ   0 = a a\ \^\ \ 0 = a a  ˆ 0=a
  2. 归零律: a     ˆ   a = 0 a\ \^\ \ a = 0 a  ˆ a=0
  3. 三元恒等式: a     ˆ   b = c a\ \^\ \ b = c a  ˆ b=c a     ˆ   c = b a\ \^\ \ c = b a  ˆ c=b b     ˆ   c = a b\ \^\ \ c = a b  ˆ c=a

题意分析:而本题其中一个条件即为三个数的异或满足: a ⊕ b ⊕ c = 0 a⊕b⊕c=0 abc=0,因此,对于此类每一个数位上满足某种条件关系的问题,可以用数位 d p dp dp 进行求解

题目要求:

  1. 1 ≤ a , b , c ≤ n 1≤a,b,c≤n 1a,b,cn
  2. a ⊕ b ⊕ c = 0 a⊕b⊕c=0 abc=0
  3. a , b , c a,b,c a,b,c 能组成三角形

step:

🎯1. d f s dfs dfs:

首先,肯定要对二进制的每个数位进行 d f s dfs dfs深搜,从而得到所有可能的情况,因为涉及二进制异或操作 ⊕ ⊕ ,则我们从这个条件出发,由 a ⊕ b ⊕ c = 0 a⊕b⊕c=0 abc=0可知,必有: a ≠ b ≠ c (1) a≠b≠c \tag{1} a=b=c(1)

d e f def def:若存在 a = = b a==b a==b,则 c = a ⊕ b = 0 c=a⊕b=0 c=ab=0,不满足条件

每一个数位上 1 的个数只能为 0 或 2 (2) 每一个数位上1的个数只能为0或2 \tag{2} 每一个数位上1的个数只能为02(2)

d e f def def:若存在 1 1 1个或 3 3 3 1 1 1的情况,则在该数位上三个数异或后为 1 1 1,则结果一定不等于 0 0 0


其次,对于三个数字,我们不可能对每个数字上的每一位进行 d f s dfs dfs,而根据三元恒等式, c = a ⊕ b c=a⊕b c=ab 可以由 a , b a,b a,b 确定,又因为三个数可以按任意顺序排列,所以,我们不妨假设 a a a 为最大数 ( a ∈ [ 1 , n ] ) (a∈[1,n]) (a[1,n]),最后的结果 ∗ 3 *3 3 即可

我们对最大数的二进制数由高位向低位进行枚举,因为需要确定 a , b a,b a,b,我们不妨设二元组 ( a i , b i ) (a_i,b_i) (ai,bi) 表示当前二进制位上 a a a b b b 的值 ( 0 / 1 ) (0/1) 0/1:

根据条件得到选取的二元组与满足条件 a , b , c a,b,c a,b,c 的隐含关系:

  1. a > b a>b a>b ( 1 , 0 ) (1,0) (1,0) 必须出现在 ( 0 , 1 ) (0,1) (0,1) 之前:

( 1 0 ) → ( 0 1 ) (3) \left( \begin{matrix} 1 \\ 0 \end{matrix} \right) → \left( \begin{matrix} 0\\ 1 \end{matrix} \right) \tag{3} (10)(01)(3)

d e f def def:假设 ( 0 , 1 ) (0,1) (0,1)出现在了 ( 1 , 0 ) (1,0) (1,0)之前:
在这里插入图片描述
( 0 , 1 ) (0,1) (0,1) ( 1 , 0 ) (1,0) (1,0)之前,则这两列排列后,b在该数位上的数大于a,此时出现了 b > a b>a b>a 的情况,与假设不符


  1. a > c a>c a>c ( 1 , 1 ) (1,1) (1,1) 必须出现在 ( 0 , 1 ) (0,1) (0,1) 之前:

( 1 1 ) → ( 0 1 ) (4) \left( \begin{matrix} 1 \\ 1 \end{matrix} \right) → \left( \begin{matrix} 0\\ 1 \end{matrix} \right) \tag{4} (11)(01)(4)

d e f def def:假设 ( 1 , 1 ) (1,1) (1,1) 出现在 ( 0 , 1 ) (0,1) (0,1) 之后:
在这里插入图片描述
由于 ( 0 , 1 ) (0,1) (0,1)异或后为1,而 ( 1 , 1 ) (1,1) (1,1)异或后为0,若 ( 1 , 1 ) (1,1) (1,1) ( 0 , 1 ) (0,1) (0,1)后,则对这两列排列后, c c c在该位置的数上大于 a a a,此时,会出现 c > a c>a c>a 的情况,与假设不符


  1. a = b ⊕ c < b + c a=b⊕c<b+c a=bc<b+c:表明必存在状态 ( a i , b i ) = ( 0 , 1 ) (a_i,b_i)=(0,1) (ai,bi)=(0,1)

必有状态 : ( 0 1 ) (5) 必有状态:\left( \begin{matrix} 0 \\ 1 \end{matrix} \right) \tag{5} 必有状态:(01)(5)

d e f def def:由于 b ⊕ c < b + c b⊕c<b+c bc<b+c,则二进制上必定存在某一位使: b i ⊕ c i < b + c b_i⊕c_i<b+c bici<b+c,那么如何实现这一状态呢?其实就是让 a i = 0 , b i = 1 , c i = 1 a_i=0,b_i=1,c_i=1 ai=0,bi=1,ci=1,此时对于加法而言: b i + c i = 2 b_i+c_i=2 bi+ci=2,而对于异或: b i ⊕ c i = 0 b_i⊕c_i=0 bici=0,存在某一位比前者小,也就实现了总体 b ⊕ c < b + c b⊕c<b+c bc<b+c


所以,若满足了上述的 5 5 5个条件,这三个数就是成立的,对于 d f s dfs dfs:

结束条件:若 p o s = 0 pos=0 pos=0且三个状态 ( 1 , 1 ) , ( 1 , 0 ) , ( 0 , 1 ) (1,1),(1,0),(0,1) (1,1)(1,0)(0,1)都出现,cnt+=1

d f s ( p o s , l i m i t , s t a t e s ) dfs(pos,limit,states) dfs(pos,limit,states):

  • p o s pos pos:表示 a a a当前所在的二进制位数
  • l i m i t limit limit:判断前面所选择的数是否全部为上限数
  • s t a t e s states states:判断是否出现过上述三种状态

🎯2. 数位 d p dp dp →记忆化搜索:

对于上述的三个状态,我们只要使其全部出现即为一种结果,因此,我们对状态进行压缩: 1 → ( 0 , 1 ) , 2 → ( 1 , 0 ) , 3 → ( 1 , 1 ) 1→(0,1),2→(1,0),3→(1,1) 1(0,1)2(1,0)3(1,1),再将数字 1 , 2 , 3 1,2,3 1,2,3 进行二进制压缩,则表示为:111,数位为1则代表对应的状态,所以结束条件即为:states=7 (111)

定义 d p dp dp 数组 dp[pos][limit][states]:表示当前数位为 p o s pos pos,前面选择的数状态为 l i m i t ( 0 / 1 ) limit(0/1) limit(0/1),且上述三个二元组的状态为 s t a t e s states states 时, a , b , c a,b,c a,b,c 三个数的选法有多少种

d p dp dp 主要为了 剪枝,增大 d f s dfs dfs在递归时的效率,防止相同的情况下重复计算


完整代码实现:

def dfs(pos,limit,states):
    if pos==0:
        return states==7

    if limit==0 and dp[pos][limit][states]!=-1:
        return dp[pos][limit][states]

    max_num=num[pos] if limit==1 else 1
    res=0
    for i in range(0,max_num+1):
        if i==0: # 如果该位置上ai为0
            # 1.(0,0)
            res+=dfs(pos-1,limit and i==max_num,states)
            # 2.(0,1)
            if states>=6: # 选(0,1)时,(1,1),(1,0)必须要出现
                res+=dfs(pos-1,limit and i==max_num,states|1) # 即为 110^001=111

        elif i==1:
            # 3.(1,0)
            res+=dfs(pos-1,limit and i==max_num,states|2) # x0x|010=x1x
            # 4.(1,1)
            res+=dfs(pos-1,limit and i==max_num,states|4) # 0xx|100=1xx

    if limit==0: # 记忆化搜索
        dp[pos][limit][states]=res
    return res


def solve(n):
    global num
    cnt=0 # 表示当前n的位数
    while n:
        cnt+=1
        num[cnt]=n&1
        n>>=1
    return dfs(cnt,1,0)*3


T=int(input())
num=[0]*32 # 最大为30位数
dp=[[[-1]*8]*2 for _ in range(32)]
for _ in range(T):
    n=int(input())
    print(solve(n))

输出结果:

在这里插入图片描述



🎇此题为2021年国赛数位 d p dp dp题,同时对思维要求也很高,今天的考点是~🎇

数位 d p dp dp + d f s dfs dfs

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DAY Ⅰ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值