蓝桥杯2024年第十五届省赛真题-魔法巡游(Python)

前言

本文参考了FJ_EYoungOneC的文章思路,并且修改了该文章的某些理解上的偏差。


一、题目

题目来源:dotcpp

题目描述

在蓝桥王国中,两位魔法使者,小蓝与小桥,肩负着维护时空秩序的使命。他们每人分别持有 N 个符文石,这些石头被赋予了强大的力量,每一块上都刻有一个介于 1 到 109 之间的数字符号。小蓝的符文石集合标记为 s1, s2, . . . , sN,小桥的则为 t1, t2, . . . , tN。

两位魔法使者的任务是通过使用符文石,在各个时空结点间巡游。每次巡游遵循这样一条法则:当小蓝使用了符文石 si 到达新的结点后,小桥必须选用一个序号更大的符文石(即某个 tj 满足 j > i)前往下一个结点。同理,小桥抵达之后,小蓝需要选择一个序号 k > j 的符文石 sk 继续他们的巡游。为了成功地穿梭时空,两个连续使用的符文石上的数字符号必须有共鸣,这种共鸣只有当数字符号中至少包含一个特定的元素——星火(数字 0)、水波(数字 2)或者风语(数字 4)时,才会发生。例如,符号序列 126, 552, 24, 4 中的每对连续符文都包含了至少一个共鸣元素,则它们是一系列成功的巡游;而如果是 15, 51, 5,则不成立,因为它们之间的共鸣元素不包含星火、水波或风语中的任意一个。

小蓝总是先启程,使用他的符文石开启巡游。

你的任务是计算这对魔法使者能够执行的最长时空巡游序列的长度。这样的序列形式为 si1, ti2, si3, ti4, . . .,其中序列索引满足 i1 < i2 < i3 < i4 < . . .,并且序列中每一对相邻的符文石都至少包含一个共鸣元素。

输入格式

输入的第一行包含一个整数 N,表示每位魔法使者持有的符文石数量。第二行包含 N 个整数 s1, s2, · · · , sN ,相邻整数之间使用一个空格分隔,表示小蓝的符文石上刻有的数字符号。第三行包含 N 个整数 t1, t2, · · · , tN ,相邻整数之间使用一个空格分隔,表示小桥的符文石上刻有的数字符号。

输出格式

输出一行包含一个整数,表示小蓝和小桥在遵守所有规则的情况下,最多能进行多少次时空巡游。

样例输入

5
126 393 581 42 44
204 990 240 46 52

样例输出

4

提示

【样例说明】

小蓝和小桥可以选择以下符文石序列进行巡游:

s1(126) → t3(240) → s4(42) → t5(52)

这里,数字 2 作为共鸣元素连接了 s1 和 t3、s4 和 t5,数字 2、4 作为共鸣元素连接了 t3 和 s4。

【评测用例规模与约定】对于 30% 的评测用例,1 ≤ N ≤ 103,1 ≤ si, ti ≤ 105。对于所有评测用例,1 ≤ N ≤ 105,1 ≤ si, ti ≤ 109。

二、思路

①题目大概意思是:

给定两个数字序列(当然理解为字符串更好操作)

L1:a1,a2,a3……an

L2:b1,b2,b3……bn

从两个序列中按次序选出一串数,使这串数长度最长。

②这串数要满足的条件:

  • 必须从L1开始选,L1选完选L2,L2选完选L1……
  • 每次选的数的下标比上一个被选的数的下标大
  • 选的相邻两个数的数位必须至少包含0,2,4中的一个(但不用两个数同时包含相同的数位
  • ③算法思想:

    按照常规思路枚举开始位置(从L1中选择)复杂度为O(n²),会超时。既然选数有个顺序,那选出来的数的长度必然就有依赖(递推)关系→DP。

    DP的初态如何确定?

    1. 向L1和L2末尾添加一项“024”(楼主是作为字符串处理的),那么选出的数字串最后一个数必然来自L1的“024”或者L2的“024”。
    2. DP从后往前递推长度。

    三、代码

    import sys
    
    
    data = sys.stdin.read().split()
    n = int(data[0])
    L1 = []
    for i in range(1,n+1):
        L1.append(data[i])
    L1.append("024")
    L2 = []
    for i in range(n+1,n+n+1):
        L2.append(data[i])
    L2.append("024")
    
    pL1 = n # 记录L1中上一个数位满足要求的数的下标
    pL2 = n
    len_L1 = [0 for i in range(n+1)] # L1中以L1[i]开始的符合题意的子序列最大长度
    len_L2 = [0 for i in range(n+1)] # L2中以L2[i]开始的符合题意的子序列最大长度
    len_L1[n] = len_L2[n] = 1 # 初态
    
    index = n-1
    while index>=0:
        if '0' in L1[index] or '2' in L1[index] or '4' in L1[index]:
            len_L1[index] = max(len_L1[index],len_L2[pL2]+1)
        if '0' in L2[index] or '2' in L2[index] or '4' in L2[index]:
            len_L2[index] = max(len_L2[index],len_L1[pL1]+1)
    
        # 注意,先更新len_L1,len_L2再更新pL1,pL2
        if '0' in L1[index] or '2' in L1[index] or '4' in L1[index]:
            pL1 = index
        if '0' in L2[index] or '2' in L2[index] or '4' in L2[index]:
            pL2 = index
        
        index -= 1
    
    print(max(len_L1)-1)
    

    tips:代码中先更新len_L1,len_L2再更新pL1,pL2的原因是避免下图中的情况:

    作者:罄竹_

    物联沃分享整理
    物联沃-IOTWORD物联网 » 蓝桥杯2024年第十五届省赛真题-魔法巡游(Python)

    发表回复