1 条题解
-
0
题目理解
我们有一个长度为 的数组 (全为正整数),以及一个长度为 的字符串 ,只包含
'L'和'R'。操作规则:
- 选择一对 ,满足 ,,
- 获得分数:(即区间 的和)
- 将该区间内所有字符变为
'.',表示这些位置不能再被使用
目标:最大化总分
关键观察
-
所有
这意味着区间和随着区间长度增加而增加。因此,在能选择的情况下,我们总希望选择尽可能大的合法区间。 -
选择的区间不能重叠(因为一旦使用,其中的字符就变成
'.',不能再被选为任何区间的端点或内部点)。
但区间可以嵌套:如果先选一个小区间,之后可以再选包含它的大区间(只要大区间的端点在小区间之外且仍未被使用)。 -
最优策略的贪心思路
由于所有数为正,我们应该优先选择当前最左边可用的'L'和当前最右边可用的'R'组成一个区间。
为什么?- 如果左边还有
'L'没被用,而右边还有'R'没被用,那么选它们之间的区间一定不差于选更小的区间,因为区间和更大。 - 选完这对 后, 和 被删除,相当于我们“向内收缩”,继续在剩下的子问题中重复这个过程。
- 如果左边还有
-
等价表述
将字符串 中的'L'视为“左括号”,'R'视为“右括号”,但注意这里的括号匹配不是任意的,而是必须左括号在右括号左边,且我们总是匹配最左边可用的'L'与最右边可用的'R'。
算法步骤
设 为长度, 从 开始索引。预处理前缀和:
区间 的和 =
双指针法:
- 初始化 (对应索引 ,因为字符串索引从 开始,但为了前缀和方便, 从 开始)
- 初始化
- 重复以下步骤直到 :
- 将 向右移动,直到 (跳过
'R') - 将 向左移动,直到 (跳过
'L') - 如果 ,则:
- 区间为 (因为数组 从 开始,而字符串 从 开始)
- 和 =
- 加到答案
- 右移一位, 左移一位(表示这两个位置已被使用)
- 将 向右移动,直到 (跳过
示例验证
以第一个样例为例:
n = 6 a = [3,5,1,4,3,2] s = LRLLLR前缀和:
初始 , :
- ,,直接取区间 ,和 =
答案 += 18,, - 现在 → 右移到 ()
→ 左移到 (),但 ,继续左移到 ?等一下,仔细看: 实际过程: 时 ,所以 左移到 , 仍不是'R',再左移到 , 也不是'R',再左移到 , 是'R',停。 此时 , ,,循环结束。 - 答案 = 18
为什么这样是对的?
因为所有 ,如果我们不选当前最左边
'L'和最右边'R'组成的区间,而是选它们内部的区间,那么:- 外部的
'L'和'R'之后可能无法再配对(因为内部被删掉后,外部端点仍可用,但内部缺失不会影响外部区间的和,反而会变小) - 更严格地:假设最优解中某次选了 ,且存在 是
'L', 是 `'R'(l, r)$ 会得到更大的和,且不破坏后续操作的可能性(因为区间变大了,删除的更多,后续可选区间是它的子集)。
因此贪心成立。
时间复杂度
每个测试用例,总 。
代码实现(已给出)
def solve(): n = int(input()) a = [0] for x in input().split(): x = int(x) a.append(a[-1] + x) s = input() ans = 0 l = 0 r = n - 1 while r > l: while l < n and s[l] == 'R': l += 1 while r >= 0 and s[r] == 'L': r -= 1 if l < r: ans += a[r + 1] - a[l] l += 1 r -= 1 print(ans)
- 1
信息
- ID
- 6301
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者