60.Cion病毒的最大收益|Marscode AI刷题

6 阅读6分钟

1.题目

问题描述

Cion 病毒入侵了 X 公司的数据库,将硬盘数据全部加密了,而解锁这些数据需要花费 Cion 币,因此你需要尽可能多地获取 Cion 币。每次加密完一份数据,Cion 病毒会留下一个 01 组成的字符串,你可以对这些字符串 s 进行任意次数以下三种操作:

  1. 使用 0 替换子串 00 并获得 a 枚 Cion 币。
  2. 使用 1 替换子串 11 并获得 b 枚 Cion 币。
  3. 从任意位置删除 0 并支付 c 枚 Cion 币。

Cion 为了加大解锁难度,要求连续两次操作的编号奇偶性不能相同。

为了赶紧修复数据,公司同意你向银行暂时借用任意枚 Cion 币,但结束时必须归还。操作按上面给出的顺序用整数 1 - 3 编号。请计算出你可以获得的最大 Cion 币是多少。

输入格式

第一行输入 4 个整数 n, a, b, c (1 ≤n≤ 10^5, 1≤ a,b,c ≤10^5).

第二行输入一个长度为 n,由 01 组成的字符串 s

保证所有测试用例的 n 的总和不超过 2*10^5

输出格式

每个测试用例输出一个整数表示你可以获得的最大 Cion 币是多少

输入样例 1

5 2 2 1

01101

输出样例 1

3

输入样例 2

6 4 3 5

110001

输出样例 2

11

输入样例 3

6 3 2 1

011110

输出样例 3

4

在第一个 Case 中,操作的最佳序列是 01101 -> 0101 -> 011 -> 01,操作顺序为 2, 3, 2,利润为 3。

2.思路

深度优先搜索(DFS)+动态规划(缓存)

2.1. 状态定义

我们使用 dfs(s, flag, a, b, c) 函数来递归地尝试从字符串 s 中获得最多的 Cion 币,其中:

  • s:当前处理的字符串。

  • flag:上一操作的编号(1,2,3),它决定了当前可以进行哪些操作。用于确保操作的编号奇偶性交替进行。

    • flag == -1 表示尚未进行操作,起始状态。
    • flag == 1 表示上一操作是奇数,接下来只能执行操作2。
    • flag == 2 表示上一操作是偶数,接下来只能执行操作1或3。

2.2. 递归展开

递归函数 dfs 会尝试对每个可能的位置进行操作,并递归处理字符串。每次操作会根据当前的 flag 决定是否能进行特定的操作。

  • 操作1(替换“00”):

    • 如果 s[i] == '0's[i+1] == '0',且上一操作不是奇数(flag != 1),那么我们可以执行操作1,替换 000,并递归调用 dfs
    • 操作后的结果通过递归返回,更新当前最大 Cion 币数。
  • 操作2(替换“11”):

    • 如果 s[i] == '1's[i+1] == '1',且上一操作不是偶数(flag != 2),那么我们可以执行操作2,替换 111,并递归调用 dfs
    • 操作后的结果通过递归返回,更新当前最大 Cion 币数。
  • 操作3(删除“0”):

    • 如果 s[i] == '0',且上一操作不是奇数(flag != 1),那么我们可以执行操作3,删除字符 0,并递归调用 dfs
    • 删除一个 0 时,会支付 c 枚 Cion 币。

2.3. 递归返回值

  • 每次递归返回的值包含两个部分:

    1. final_s:操作后的字符串。虽然题目要求的结果并不涉及这个值,但我们保留它以便调试或理解操作的最终结果。
    2. res:表示当前递归状态下,能够获得的最大 Cion 币数。

2.4. 缓存优化

  • 为了避免重复计算相同的子问题,使用 @lru_cache(maxsize=None)dfs 函数进行缓存。

    • lru_cache 将会缓存已经计算过的 dfs(s, flag) 的结果,当相同的 sflag 再次出现时,直接返回缓存的结果,避免重复计算,显著提高性能。

2.5. 主函数

主函数 solution(n, a, b, c, s) 初始化递归调用,设置初始的 flag = -1(表示没有进行任何操作),并传入字符串 s。最后返回最大 Cion 币数 res

3.代码

from functools import lru_cache #对子问题结果进行缓存,从而避免重复计算
@lru_cache(maxsize = None) # 使用 缓存机制 记录已经计算过的 s 和 flag 状态。
def dfs(s, flag, a, b, c): # flag 表示上一操作的编号(操作的奇偶性)
    res = 0 # 当前最大收益
    final_s = s # 记录当前最优路径的字符串状态
    for i in range(len(s)):
        # 替换'11'为'1'
        if i < len(s) - 1 and s[i] == '1' and s[i + 1] == '1' and flag != 2: # 上一次操作编号不能是偶数
            ss, result = dfs(s[:i]+s[i+1:],2,a,b,c) # 使用深度优先搜索处理新字符串 s[:i] + s[i+1:],即去掉一个 1
            if res < result + b:
                final_s, res = ss, result + b
        # 替换'00'为'0'
        elif i < len(s) - 1 and s[i] == '0' and s[i + 1] == '0' and flag != 1: # 上一次操作编号不能是偶数
            ss, result = dfs(s[:i]+s[i+1:],1,a,b,c) # 使用深度优先搜索处理新字符串 s[:i] + s[i+1:],即去掉一个 1
            if res < result + a:
                final_s, res = ss, result + a
        # 删除'0'
        elif s[i] == '0' and flag != 1: # 上一次操作编号不能是偶数
            ss, result = dfs(s[:i]+s[i+1:],1,a,b,c) # 使用深度优先搜索处理新字符串 s[:i] + s[i+1:],即去掉一个 1
            if res < result - c:
                final_s, res = ss, result - c
    return final_s, res
def solution(n, a, b, c, s):
    # Please write your code here
    final_s, res = dfs(s, -1, a, b, c) # flag初始化为-1,第一次操作可以是1,2,3任意一个
    return res

if __name__ == "__main__":
    #  You can add more test cases here
    print(solution(5, 2, 2, 1, "01101") == 3 )
    print(solution(6, 4, 3, 5, "110001") == 11 )
    print(solution(6, 3, 2, 1, "011110") == 4 )

@lru_cache(maxsize=None) 是 Python 中 functools 模块的一个装饰器,它用于对函数进行缓存,从而提高函数的性能,特别是在需要多次调用同一函数时。

具体作用:

  1. 缓存函数的返回值: 当函数被调用时,lru_cache 会记录输入参数与返回值的对应关系。如果函数使用相同的参数再次被调用,lru_cache 会直接返回缓存的结果,而不是重新计算。这有助于避免重复计算相同的结果,提高程序的效率。
  2. LRU (Least Recently Used) 策略: lru_cache 使用最少最近使用(LRU)算法来管理缓存。如果缓存的条目数量超过了 maxsize 设置的限制(默认为 128),它会删除最久未使用的条目,以释放内存。maxsize=None 意味着没有缓存大小限制,缓存将一直存储所有计算结果,直到程序退出。

例子:

假设有一个递归函数,我们希望避免对同一输入值的重复计算,可以使用 @lru_cache 来优化它。

from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))  # 第一次调用,计算过程
print(fibonacci(10))  # 第二次调用,直接从缓存中获取结果

4.参考资料

青训营笔记之Cion 勒索病毒的最大收益 | 豆包MarsCode AI刷题问题描述 小S在处理一个安全事故时发现,Ci - 掘金

AI刷题中档题 Cion 勒索病毒的最大收益 解答 | 豆包MarsCode AI刷题Cion 勒索病毒的最大收益 问题 - 掘金