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

79 阅读5分钟

Cion 勒索病毒的最大收益

问题描述

小S在处理一个被Cion病毒攻击的数据库时,需要对一个包含 01 的二进制字符串进行特定的操作,来赚取尽可能多的Cion币。规则如下:

  1. 使用 一个 0 替换子串 00,可以获得 a 枚Cion币。
  2. 使用 一个 1 替换子串 11,可以获得 b 枚Cion币。
  3. 删除一个 0,需要支付 c 枚Cion币。

限制条件

  • 连续两次操作的编号不能具有相同的奇偶性
    例如:若第一个操作是 00 替换,操作编号是偶数,则下一次操作的编号必须是奇数。

目标是:在满足上述规则的情况下,最大化可以获得的Cion币总数。


算法分析

为了解决这个问题,采用了基于深度优先搜索(DFS)+动态规划(缓存)的策略。代码利用了Python中的 functools.lru_cache 对子问题结果进行缓存,从而避免重复计算。

以下是代码的分步解析及详细解释:


代码解析

主函数

python
复制代码
def solution(n, a, b, c, s):
    final_s, res = dfs(s, -1, a, b, c)
    print(final_s)
    return res
  1. 参数说明

    • n:字符串的长度。
    • a:替换 000 时获得的Cion币数量。
    • b:替换 111 时获得的Cion币数量。
    • c:删除 0 时需要支付的Cion币数量。
    • s:输入的01字符串。
  2. 逻辑

    • 调用 dfs 函数开始搜索,返回 最终操作后的字符串最大Cion币收益
    • 打印操作完成后的字符串,用于观察变化过程。

深度优先搜索函数

@lru_cache(maxsize=None)
def dfs(s, flag, a, b, c):
    res = 0  # 当前最大收益
    final_s = s  # 记录当前最优路径的字符串状态
  • @lru_cache(maxsize=None)

    • 使用 缓存机制 记录已经计算过的 sflag 状态。
    • 防止对相同状态的重复计算,提高效率。
  • 变量初始化

    • res:当前状态下的最大Cion币收益。
    • final_s:当前状态下的最终字符串。

操作1:替换 000

if 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)
    if res < result + a:
        final_s, res = ss, result + a
  1. 条件检查

    • s[i] == '0' and s[i+1] == '0':当前位置及下一个字符是连续的 00
    • flag != 1:上一次操作的编号不能是奇数。
  2. 操作逻辑

    • 使用深度优先搜索处理新字符串 s[:i] + s[i+1:],即去掉一个 0
    • 操作后将收益增加 a
  3. 结果更新

    • 如果操作后的总收益 result + a 大于当前最大值 res,更新 resfinal_s

操作2:替换 111

elif 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)
    if res < result + b:
        final_s, res = ss, result + b
  1. 条件检查

    • s[i] == '1' and s[i+1] == '1':当前位置及下一个字符是连续的 11
    • flag != 2:上一次操作的编号不能是偶数。
  2. 操作逻辑

    • 使用深度优先搜索处理新字符串 s[:i] + s[i+1:],即去掉一个 1
    • 操作后将收益增加 b
  3. 结果更新

    • 如果操作后的总收益 result + b 大于当前最大值 res,更新 resfinal_s

操作3:删除 0

elif s[i] == '0' and flag != 1:
    ss, result = dfs(s[:i]+s[i+1:], 1, a, b, c)
    if res < result - c:
        final_s, res = ss, result - c
  1. 条件检查

    • s[i] == '0':当前字符为 0
    • flag != 1:上一次操作的编号不能是奇数。
  2. 操作逻辑

    • 使用深度优先搜索处理新字符串 s[:i] + s[i+1:],即删除一个 0
    • 操作后收益减少 c
  3. 结果更新

    • 如果操作后的总收益 result - c 大于当前最大值 res,更新 resfinal_s

返回结果

return final_s, res

返回操作后的字符串和当前最大收益。


代码:

python实现代码如下:

from functools import lru_cache

@lru_cache(maxsize = None)
def dfs(s,flag,a,b,c):
    res = 0
    final_s = s
    for i in range(len(s)):
        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)
            if res < result+b:
                final_s,res = ss,result+b
        elif i < len(s)-1 and s[i] == '0' and s[i+1] == '0' and 1!=flag:
            ss,result = dfs(s[:i]+s[i+1:],1,a,b,c)
            if res < result+a:
                final_s,res = ss,result+a
        elif s[i] == '0' and 1 != flag:
            ss,result = dfs(s[:i]+s[i+1:],1,a,b,c)
            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)
    print(final_s)
    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 )

复杂度分析

  1. 时间复杂度

    • 每个状态 s 被缓存后仅访问一次,最多有 2^n 个可能的状态。
    • 每次递归中,最多遍历 len(s) 次,因此时间复杂度为 O(n * 2^n)
  2. 空间复杂度

    • 缓存使用 lru_cache,需要额外的空间存储子问题解,空间复杂度为 O(2^n)

测试样例解析

样例1

  • 输入:n = 5, a = 2, b = 2, c = 1, s = "01101"

  • 输出:3

  • 操作顺序:

    1. 替换 000,获得 2。
    2. 删除一个 0,支付 1。

样例2

  • 输入:n = 6, a = 4, b = 3, c = 5, s = "110001"

  • 输出:11

  • 操作顺序:

    1. 替换 111,获得 3。
    2. 替换 000,获得 4。
    3. 替换 000,获得 4。

总结

  • 此算法通过深度优先搜索和缓存技术有效解决了复杂的操作序列问题。
  • 在规则的限制下,最大化Cion币收益的计算变得可行且高效。