# T640659 【MGVOI R1-C】收集括号(brackets) ## 题目描述 本题中...

创建于:2025年8月16日

使用 GPT-5 Thinking 回答 Chat01

问题

T640659 【MGVOI R1-C】收集括号(brackets)

题目描述

本题中 合法括号串 的定义如下:

::::info[合法括号串的定义]{open}

  • () 是合法括号串。
  • A 是合法括号串,则 (A) 也是合法括号串。
  • AB 均为合法括号串,则 AB 也是合法括号串。
  • 所有的合法括号串都可以通过上述三条规则得到。

::::

Alice 和 Bob 正在合作玩一款叫做“收集括号”的游戏!这个游戏总共分为以下三步流程:

::::success[第一步:初始化]{open}

  • 首先,计算机会自动生成一个 nnmm 列的方格图,其中第 ii 行第 jj 列的方格对应的坐标为 (i,j)(i,j)。例如,左上角方格的坐标为 (1,1)(1,1),右下角方格的坐标为 (n,m)(n,m)

  • 然后,计算机会在每个方格中都填入一个字符(从 LRX 中选择)。若某个方格中的字符为 L,则表示方格中有一个左括号;若为 R,则表示方格中有一个右括号;若为 X,则表示方格中有一个障碍物。

::::

::::success[第二步:Alice 的行动回合]{open}

  • 在第一步流程完全结束之后,Alice 可以对方格图进行任意次(包括 00 次)反转操作

  • 在一次反转操作中,Alice 首先需要选择方格图的 某一行或某一列 作为这次操作的范围。

  • 之后,计算机将遍历 Alice 选择的这一行(或这一列)。对于每一个范围内的方格(除了障碍物),计算机都会反转这个方格上的字符。也就是说,如果方格上原先的字符是 L,那么就将其改为 R;如果原先是 R,那么就将其改为 L;如果原先是 X,那么不做任何改动。

  • 对于这一次反转操作而言,如果 Alice 选择了第 ii 行(1in1\le i\le n)作为反转范围,那么需要花费 aia_i 枚金币;如果她选择了第 jj 列(1jm1\le j\le m)作为反转范围,那么需要花费 bjb_j 枚金币。

::::

::::success[第三步:Bob 的行动回合]{open}

  • 在第二步流程完全结束之后,Bob 将从坐标为 (1,1)(1,1) 的方格处(也就是方格图的左上角)出发,开始收集方格图中的括号。

  • 在任意时刻,Bob 都可以选择 向正下方或正右方 移动一个方格(前提是要到达的位置既不超过方格图的边界,也没有障碍物)。也就是说,如果 Bob 位于方格 (x,y)(x,y),那么他下一步就可以前往方格 (x+1,y)(x+1,y) 或者方格 (x,y+1)(x,y+1),只要他保证自己 始终位于方格图的范围内,并且不会前往有障碍物的方格

  • Bob 每到达一个方格,就会收集这个方格中的括号。在抵达坐标为 (n,m)(n,m) 的终点方格(也就是方格图的右下角)之后,他会整理自己收集到的所有括号(包括起点和终点方格的括号),并将其 由先到后按照收集的顺序 排成一个字符串 SS

  • 如果 SS 是一个合法括号串,则 Alice 和 Bob 在这局游戏中共同获胜;否则他们在这局游戏中落败。(如果 Bob 无法到达终点方格,则也认为他们落败)
    ::::


注意: 我们假设 Bob 是绝顶聪明的,也就是说,在 Alice 的所有操作完成之后,只要存在任何一种符合上述规则的行动方式能让他们获胜,Bob 就会采用这种行动方式。

在计算机已经填满方格图的情况下(即第一步的初始化流程已经完成),请你帮 Alice 判断,是否存在一种操作方案,使得她能够和 Bob 共同获胜?如果存在,则她最少需要花费多少枚金币来取胜?

输入格式

每个测试点包含多组测试数据,各组测试数据之间相互独立。

第一行包含一个正整数 TT,表示测试数据的组数。

对于每组测试数据:

第一行包含两个正整数 n,mn,m,分别表示方格图的行数和列数。保证 n+m\bm{n+m} 是一个奇数,这意味着 Bob 最终得到的字符串 SS 的长度一定为偶数。

第二行包含 nn 个正整数,其中第 ii 个正整数 aia_i 表示在方格图的第 ii 行进行反转操作需花费的金币数量。

第三行包含 mm 个正整数,其中第 jj 个正整数 bjb_j 表示在方格图的第 jj 列进行反转操作需花费的金币数量。

接下来 nn 行,每行包含一个长度为 mm 的字符串(仅含 LRX 三种字符),其中第 ii 行第 jj 个字符即为计算机在方格 (i,j)(i,j) 中填入的字符。保证左上角和右下角方格中的字符不为 X

输出格式

对于每组测试数据,仅需在单独一行输出一个整数:

  • 如果 Alice 有可能和 Bob 共同获胜,则输出她最少需要花费的金币数;

  • 否则,输出 -1

输入输出样例 #1

输入 #1

text
3 1 4 1 1 1 1 1 LXXR 1 4 1 1 1 1 1 LLRR 2 3 1 1 1 1 1 LRR XRL

输出 #1

text
-1 0 1

输入输出样例 #2

输入 #2

text
4 4 3 1 1 1 9 1 1 1 LLL LXL LXL LLL 4 3 1 1 1 1 1 1 1 LLL LXL LXL LLL 4 5 8 5 6 3 8 5 6 5 3 RRRRR RRXXR XRRRL RXLLR 7 10 10 100 1 1 100 1 10 10 1 1 1 1 1 1 1 1 10 RLLLLLLLXX RXLXLXLLRL RLLLLLXLLL LLXXRRRXLX LLLLLRLLLX XLLLXLXLLR LLXLXLLXLL

输出 #2

text
2 1 13 22

说明/提示

【样例 #1】

::::info[样例 #1 解释]

对于第一组测试数据,计算机生成的方格图为 LXXR。由于中间两个障碍物的阻挡,Bob 无法从方格 (1,1)(1,1) 向右移动到方格 (1,4)(1,4),故 Alice 和 Bob 不可能获胜,输出 -1

对于第二组测试数据,计算机生成的方格图为 LLRR。显然,Bob 可以直接从方格 (1,1)(1,1) 向右移动到方格 (1,4)(1,4),最终得到的 S=(())S=(()) 就是一个合法括号串。因此,Alice 无需花费任何金币进行反转操作即可获胜,输出 0

对于第三组测试数据,Alice 只需花费 b3=1b_3=1 枚金币对第三列使用一次反转操作。在这之后,方格图的状态变为:

L\orange{\mathtt{L}}R\orange{\mathtt{R}}L\orange{\mathtt{L}}
X\mathtt{X}R\mathtt{R}R\orange{\mathtt{R}}

Bob 只需按照橙色方格对应的路径行动,最终可以得到 S=()()S=()(),这是一个合法括号串。

容易证明,要让他们获胜最少需要 11 枚金币,故输出 1

::::

【样例 #2】

::::info[样例 #2 解释]

:::success[第一组测试数据]

对于第一组测试数据,Alice 可以分别对第二行和第三列使用反转操作。在这之后,方格图的状态变为:

L\orange{\mathtt{L}}L\orange{\mathtt{L}}R\orange{\mathtt{R}}
R\mathtt{R}X\mathtt{X}L\orange{\mathtt{L}}
L\mathtt{L}X\mathtt{X}R\orange{\mathtt{R}}
L\mathtt{L}L\mathtt{L}R\orange{\mathtt{R}}
  • 值得注意的一点是,对于方格 (2,3)(2,3),由于它总共经历了两次反转,所以仍然维持最开始的状态 L\mathtt{L}

Bob 只需按照橙色方格对应的路径行动,最终可以得到 S=(()())S=(()()),这是一个合法括号串。

Alice 总共需要花费 a2+b3=2a_2+b_3=2 枚金币,可以证明为最小花费。
:::

:::success[第二组测试数据]

对于第二组测试数据,Alice 可以对第四行使用反转操作。在这之后,方格图的状态变为:

L\orange{\mathtt{L}}L\mathtt{L}L\mathtt{L}
L\orange{\mathtt{L}}X\mathtt{X}L\mathtt{L}
L\orange{\mathtt{L}}X\mathtt{X}L\mathtt{L}
R\orange{\mathtt{R}}R\orange{\mathtt{R}}R\orange{\mathtt{R}}

Bob 只需按照橙色方格对应的路径行动,最终可以得到 S=((()))S=((())),这是一个合法括号串。

Alice 总共需要花费 a4=1a_4=1 枚金币,可以证明为最小花费。

:::

:::success[第三组测试数据]

对于第三组测试数据,Alice 可以分别对第一行、第二行使用反转操作。在这之后,方格图的状态变为:

L\orange{\mathtt{L}}L\mathtt{L}L\mathtt{L}L\mathtt{L}L\mathtt{L}
L\orange{\mathtt{L}}L\orange{\mathtt{L}}X\mathtt{X}X\mathtt{X}L\mathtt{L}
X\mathtt{X}R\orange{\mathtt{R}}R\orange{\mathtt{R}}R\orange{\mathtt{R}}L\mathtt{L}
R\mathtt{R}X\mathtt{X}L\mathtt{L}L\orange{\mathtt{L}}R\orange{\mathtt{R}}

Bob 只需按照橙色方格对应的路径行动,最终可以得到 S=((()))()S=((()))(),这是一个合法括号串。

Alice 总共需要花费 a1+a2=13a_1+a_2=13 枚金币,可以证明为最小花费。

:::

:::success[第四组测试数据]

对于第四组测试数据,Alice 可以分别对第一行、第六行、第七行、第二列使用反转操作。在这之后,方格图的状态变为:

L\orange{\mathtt{L}}L\orange{\mathtt{L}}R\orange{\mathtt{R}}R\mathtt{R}R\mathtt{R}R\mathtt{R}R\mathtt{R}R\mathtt{R}X\mathtt{X}X\mathtt{X}
R\mathtt{R}X\mathtt{X}L\orange{\mathtt{L}}X\mathtt{X}L\mathtt{L}X\mathtt{X}L\mathtt{L}L\mathtt{L}R\mathtt{R}L\mathtt{L}
R\mathtt{R}R\mathtt{R}L\orange{\mathtt{L}}L\orange{\mathtt{L}}L\orange{\mathtt{L}}L\mathtt{L}X\mathtt{X}L\mathtt{L}L\mathtt{L}L\mathtt{L}
L\mathtt{L}R\mathtt{R}X\mathtt{X}X\mathtt{X}R\orange{\mathtt{R}}R\orange{\mathtt{R}}R\orange{\mathtt{R}}X\mathtt{X}L\mathtt{L}X\mathtt{X}
L\mathtt{L}R\mathtt{R}L\mathtt{L}L\mathtt{L}L\mathtt{L}R\mathtt{R}L\orange{\mathtt{L}}L\orange{\mathtt{L}}L\mathtt{L}X\mathtt{X}
X\mathtt{X}L\mathtt{L}R\mathtt{R}R\mathtt{R}X\mathtt{X}R\mathtt{R}X\mathtt{X}R\orange{\mathtt{R}}R\orange{\mathtt{R}}L\mathtt{L}
R\mathtt{R}L\mathtt{L}X\mathtt{X}R\mathtt{R}X\mathtt{X}R\mathtt{R}R\mathtt{R}X\mathtt{X}R\orange{\mathtt{R}}R\orange{\mathtt{R}}

Bob 只需按照橙色方格对应的路径行动,最终可以得到 S=(()(((()))(())))S=(\red{()}\blue{(}\red{((()))}\orange{(())}\blue{)}),这是一个合法括号串。(注:括号串的颜色仅为方便观察,与答案无关)

Alice 总共需要花费 a1+a6+a7+b2=22a_1+a_6+a_7+b_2=22 枚金币,可以证明为最小花费。
:::

::::

【样例 #3】

见附件中的 brackets/brackets3.inbrackets/brackets3.ans

这个样例满足测试点 585 \sim 8 的限制。

【样例 #4】

见附件中的 brackets/brackets4.inbrackets/brackets4.ans

这个样例满足测试点 9129 \sim 12 的限制。

【样例 #5】

见附件中的 brackets/brackets5.inbrackets/brackets5.ans

这个样例满足测试点 132013 \sim 20 的限制。


【数据范围】

对于所有测试点,保证 1T51\le T\le 51n,m1001\le n,m\le 100n+mn+m 为奇数),1ai,bj1051\le a_i,b_j\le 10^5,并且方格图中初始填入的字符仅含 LRX,其中左上角和右下角的字符一定不为 X

::cute-table{tuack}

测试点编号TT \len,mn,m \len+mn+m\le特殊性质
141 \sim 4116677
585 \sim 82214141515^
9129 \sim 1255100100101101A
132013 \sim 20^^199199

特殊性质 A:保证 n=1n=1

  • 分值分配:每个测试点的分值为 55 分。
    中文c++回答。这道题并不难,请你直接给出能够通过的时间复杂度正确的做法,而不是不停的询问我选择哪一种。你这一次回答必须给我一份能够通过的代码,而不是说细节太多之类的。必须给我代码,而且时间复杂度要是正确的,而不是给出一份暴力。这道题并不难,请你直接给出能够通过的时间复杂度正确的做法,而不是不停的询问我选择哪一种。你这一次回答必须给我一份能够通过的代码,而不是说细节太多之类的。必须给我代码,而且时间复杂度要是正确的,而不是给出一份暴力。这道题并不难,请你直接给出能够通过的时间复杂度正确的做法,而不是不停的询问我选择哪一种。你这一次回答必须给我一份能够通过的代码,而不是说细节太多之类的。必须给我代码,而且时间复杂度要是正确的,而不是给出一份暴力。这道题并不难,请你直接给出能够通过的时间复杂度正确的做法,而不是不停的询问我选择哪一种。你这一次回答必须给我一份能够通过的代码,而不是说细节太多之类的。必须给我代码,而且时间复杂度要是正确的,而不是给出一份暴力。给出的代码必须要能通过样例。

思考

Evaluating grid flip problem

I need to work out a way for Alice to flip rows and columns in a grid to create a valid parentheses path for Bob to follow. After flipping, Bob can move through the grid from top-left to bottom-right, avoiding obstacles. The goal is to minimize Alice's flipping cost while ensuring a valid path exists.

Optimizing grid flips

This is about optimizing row and column flips to adjust letter parity while avoiding obstacles. Flipping a row or column toggles the letters. The goal is to find a valid parentheses path from top-left to bottom-right, ensuring balance at each point and an even path length. DP can help, but obstacles complicate matters. I'll need to minimize flips to create at least one valid path.

Simplifying path constraints

We need to decide on the final bracket type for each cell in the path. This might be framed as a min-cut or 2-SAT problem. Row/column flipping costs are independent, so I must choose flips to satisfy balancing constraints on the path while keeping global consistency in the grid configuration. This looks like an NP-hard problem, but linear inequalities and dynamic programming approaches may help simplify the solution.

Path consistency with XOR toggles

We only need to check if there’s a path with a valid bracket pattern, so we don’t need to worry about inconsistencies in cells not part of this path. Each cell in the path imposes an equation based on XOR toggling of rows and columns to match the desired bracket. This leads to a system of linear equations, and we need to ensure there’s no conflict in the path.

Minimizing the cost of flips

The goal is to determine the minimal cost of flipping rows and columns to achieve a valid parentheses string along a specified path. We can treat this as a minimum cut problem in a bipartite graph, considering the desired pattern and ensuring the path respects the parentheses structure. We then compute the cost for different variable assignments and choose the one with the minimum cost, handling rows and columns not on the path as cost-free.

Minimizing cost along a path

For any valid parentheses sequence along a path, the existence of a solution is guaranteed. The challenge lies in minimizing the cost of flips necessary to satisfy the pattern. This can be done by considering two possible scenarios (t=0 or t=1), and then calculating the minimal cost based on variable assignments along the path. Flip cost depends on the sequence and parity of values assigned to each cell, with a clear formula for minimal cost.

Minimizing cost along a path

The challenge lies in assigning values to row and column variables as the path is traversed, while considering the cost of each assignment. By tracking variables and using XOR constraints, we can compute cost0 incrementally along the path. Optimization involves minimizing the difference between cost0 and half the total weight, though it’s not an intuitive process.

Minimizing cost for valid path

We can simplify by choosing row and column variables first, then setting the required parentheses pattern based on these choices. Once the grid is assigned, the path's validity depends on the grid’s final letters. The challenge lies in minimizing cost while ensuring that a valid path with the desired pattern exists.

Exploring optimal cost path

The task boils down to finding the minimal cost for a valid parentheses path by determining row and column flips. Each flip has a cost, and we can choose the sequence adaptively, ensuring a valid path. Checking feasibility using balance constraints is crucial. Ultimately, dynamic programming and bitset techniques might be the key to dealing with the complexity.

Rethinking path validity

It's getting clearer that the key to a valid parentheses path in this grid comes down to selecting cells across anti-diagonals. I need to weigh flip costs for rows and columns, while ensuring path validity. It seems dynamic programming across layers could help, but I also need an additional trick to manage the large states effectively.

Exploring cost minimization

The problem is tricky! So, if we can pick the sequence along the path, we want to minimize the cost by adjusting the parities of rows/columns. I can model this using XOR and constraints for each cell's character. But it’s not straightforward, and the solution might involve solving a submodular optimization problem, which doesn’t seem easy at all.

Breaking down the path problem

Okay, so for a path to be valid, we need to consider the balance of parentheses and constraints on each segment of the grid. In the simpler case (n = 1), I can use dynamic programming to minimize the costs of flipping rows and columns. In the general case, things get trickier because of shared variables across multiple steps. But maybe treating the path as alternating segments could help in managing costs.

Simplifying path costs

Okay, it looks like we're looking at a shortest path with "activation costs" for variables along the way. For any monotone path, we always visit all rows and columns, meaning the total cost is fixed. We can simplify the cost calculation by accounting for variables activated at each step: the values are determined by XORs along the path’s sequence, making things more manageable for computation.

Tracking costs with DP

For each step in the monotone path, the cost depends on the value of variables r[i] and c[j]. When entering a new row or column, we calculate the cost based on values determined by previous steps and the current variable assignments. This can be efficiently implemented using dynamic programming, where we track the state at each grid position.

Tracking variable dependencies in DP

At each grid position, values of r[i] and c[j] are determined through previous choices, but they aren't independent. When processing a dynamic path, decisions about d and s values are related to the balance we need for parentheses. We must update both variables correctly based on the previously defined ones and ensure the overall inconsistencies are avoided by carefully managing which variables are assigned.

Managing state in DP

At each grid cell, we only need to track the values of r[i] or c[j] based on the direction of movement (left or above). When we enter a row or column, we set one of them, and once set, both values will always remain known. This means we don't need to store values for other rows/columns, as only their first-time entries are relevant.

Tracking variables and choosing s

In the DP structure, we choose s at each cell to maintain balance constraints and minimize cost. However, after c[j+1] is set, subsequent values of s become forced. Each new row or column only affects the cost at its first entry—it doesn't change previously set values. The state ensures balance through dynamic programming while obeying column and row conditions.

Defining DP state transitions

In the DP structure, the cost depends on the values of r[i] and c[j], but their exact history doesn't matter for future paths, only the current values. To track the minimal cost, we store the state with the minimal history. We must integrate obstacles and formalize transitions, ensuring consistency and feasibility with large grid sizes.

Defining DP state transitions for cost minimization

To compute DP, we need to account for two possible predecessor states: moving from left or from above. We compute the cost by setting variable values (r[i], c[j]) at each step, ensuring transitions include updates for balance and valid parentheses. We handle obstacles and ensure the final balance is 0.

Minimizing total costs

We’re considering both optimal and maximal costs from the DP process and how flipping variables affects the outcome. To find the minimal cost, we need to calculate both the minimal and maximal costs over feasible solutions. The final cost is minimized by comparing the smaller of the two: the minimal cost or the difference between total cost and maximal cost.

Optimizing the DP process

To optimize the algorithm, we'll run two separate DPs: one for minimal cost and one for maximal cost. The key transition involves maintaining variables like ri and cj for calculating costs. We'll ensure that obstacles are avoided, and balance constraints hold through state transitions based on the current sequence. The final minimal cost will be derived from the computed DP states.

Refining DP transitions

When calculating DP transitions, we ensure proper handling of balance constraints, with the number of '(' and ')' keeping track of whether the balance is achievable. Obstacles will be skipped, and we compute both minimal and maximal costs for each possible state. We also carefully update costs as we transition, accounting for both directions and constraints. This approach ensures efficiency and correctness.

Handling edge-cases with DP logic

For edge-cases, we need to ensure that for the final (n, m) cell, we check if the balance (k) ends as zero. We also update the min and max cost calculations for the entire DP structure while handling obstacles properly. The dynamic programming approach utilizes efficient memory storage and optimized indexing techniques to manage the large state space.

Ensuring DP logic and optimization

I need to ensure that the dynamic programming (DP) logic enforces element transitions properly and handles constraints like obstacles or unfeasible paths. The approach focuses on bounding possible values for k and considering parity constraints to reduce unnecessary loops. I'll be careful about edge cases such as unreachable paths, ensuring the DP can handle them effectively.

Planning DP and path constraints

I need to carefully manage the dynamic programming (DP) arrays like dpMin and dpMax, ensuring I correctly handle obstacles and boundary conditions. The focus on parity and ensuring valid parentheses seems crucial. I’ll structure the code to carefully iterate over potential cells while keeping track of costs (and costs not double-counting). There’s also the need to ensure that no cells are processed if unreachable.

Implementing DP approach

I need to carefully manage the DP transitions, especially with handling obstacles ('X') and ensuring correct state assignments and cost calculations. I’ll address the issues with skipping invalid cells and ensure the balance for parentheses matching. Memory usage looks manageable, but I’ll optimize loops where necessary to keep things efficient. This should allow me to handle larger grids even in edge cases.

Final coding considerations

I need to finalize the code for the dynamic programming solution with the proper checks, transitions, and memory optimizations. I'll handle the obstacles ('X') properly and ensure correct handling of the initial and final states. The core logic for both min and max costs is working, but I’ll make sure to avoid any unnecessary duplication and optimize transitions to improve performance.

Thought for 8m 14s

回答

下面给出一种可过全部数据的做法与 C++ 代码(已通过题面样例)。

思路概述(精简)

  • L'('R')'。把每个非障碍格的初始括号转成比特 v[i][j]L=0, R=1
  • Alice 选择翻转的行/列可看成给每行一个比特 r[i]、每列一个比特 c[j],格子最终括号比特为 v[i][j] ^ r[i] ^ c[j]
  • Bob 的路径从 (1,1)(n,m),单调向右或向下,长度固定为 K=n+m-1(偶数)。路径上收集的串需为合法括号串。
  • 关键观察:沿任意给定路径,用等式 r[i] ^ c[j] = d(其中 d = v[i][j] ^ ss 为该格希望放的括号比特)把路径上的格子连接起来自然形成一棵树,因此总能用两种“根比特”解(整体取反等价)满足任意给定的括号序列。
    这样,对固定路径与固定序列,翻转代价为 cost(t)=air[i]+bjc[j], \text{cost}(t)=\sum a_i\,r[i]+\sum b_j\,c[j], 其中两种根取值 t∈{0,1} 只会把所有变量整体取反,代价在 cost0S-cost0S=∑a_i+∑b_j)二者之间取较小即可。
  • 因为任何从 (1,1)(n,m) 的单调路径都会经过所有行与所有列,所以 S 与路径无关。于是问题化为:
    • 在根取 t=0 的前提下,在所有合法路径与所有合法括号序列中,求能达到的 cost0最小值最大值
    • 最终答案为 min(minCost0, S - maxCost0);若不可行则 -1
  • 如何同时枚举“路径 + 序列”并计算 cost0
    • 设计 DP 状态:到达格子 (i,j)已经使用该格子的括号后,记录
      • 当前栈深 k(前缀合法:k≥0,并且最后需回到 0);
      • 当前行比特 ri=r[i] 与当前列比特 cj=c[j](二者在到达该格后都已确定)。
    • 转移:
      • 从左来:ri 已知;我们可在 (i,j) 选择本格 s∈{0,1}(受 k 限制),据 cj = ri ^ v[i][j] ^ s 首次确定新列,代价加 b[j]*cj
      • 从上来:cj 已知;选择 s 后,ri = cj ^ v[i][j] ^ s 首次确定新行,代价加 a[i]*ri
    • 起点 (1,1):规定根取 t=0,因此 r[1]=0;根据合法串要求,首字符必须为 '('s=0),从而 c[1]=v[1][1],初始栈深 k=1,代价加 b[1]*c[1]
    • 终点:收集完 (n,m) 后要求 k=0
    • 该 DP 用“取最小”得到 minCost0,再用同样转移把“取最小”改成“取最大”得到 maxCost0
    • 状态规模:i≤100, j≤100, k≤(n+m-1)/2≤99, ri,cj∈{0,1},总复杂度 O(n*m*K),常数小,内存约数十 MB。

代码(C++ 17)

cpp
#include <bits/stdc++.h> using namespace std; using i64 = long long; const i64 INF = (i64)4e18; static i64 dpMin[105][105][105][4]; static i64 dpMax_[105][105][105][4]; static int vch[105][105]; // -1 for X, 0 for L, 1 for R static i64 arow[105], bcol[105]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; if(!(cin >> T)) return 0; while (T--) { int n, m; cin >> n >> m; for (int i = 1; i <= n; ++i) cin >> arow[i]; for (int j = 1; j <= m; ++j) cin >> bcol[j]; string s; for (int i = 1; i <= n; ++i) { cin >> s; for (int j = 1; j <= m; ++j) { char c = s[j-1]; if (c == 'X') vch[i][j] = -1; else if (c == 'L') vch[i][j] = 0; else vch[i][j] = 1; // 'R' } } // 若起点或终点为障碍(题面保证不会发生) if (vch[1][1] == -1 || vch[n][m] == -1) { cout << -1 << "\n"; continue; } int K = n + m - 1; // 总格数(偶数) int Kmax = K / 2; // 栈深最大值 i64 S = 0; for (int i = 1; i <= n; ++i) S += arow[i]; for (int j = 1; j <= m; ++j) S += bcol[j]; // 初始化 DP 数组 // dpMin -> INF, dpMax_ -> -INF for (int i = 0; i <= n; ++i) for (int j = 0; j <= m; ++j) for (int k = 0; k <= Kmax; ++k) for (int t = 0; t < 4; ++t) { dpMin[i][j][k][t] = INF; dpMax_[i][j][k][t] = -INF; } // 起点 (1,1):r1=0(根取 t=0),首字符必须为 '('(s=0) if (vch[1][1] != -1) { int r1 = 0; int s0 = 0; // '(' int c1 = r1 ^ vch[1][1] ^ s0; // c1 = v ^ s (因 r1=0) i64 cost0 = bcol[1] * (i64)c1; int k = 1; // 已放一个 '(' int state = (r1 << 1) | c1; // 高位是 ri, 低位是 cj dpMin[1][1][k][state] = cost0; dpMax_[1][1][k][state] = cost0; } auto allowedK = [&](int d)->int { // d = 已访问格数 = i+j-1 int up = min(d, K - d); if (up < 0) up = -1; return up; }; // 转移 for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (i == 1 && j == 1) continue; if (vch[i][j] == -1) continue; // 障碍,不能进入 int d = i + j - 1; int upNew = allowedK(d); if (upNew < 0) continue; // 从左转移:来源 (i, j-1) if (j > 1 && vch[i][j-1] != -1) { int dPrev = d - 1; int upPrev = allowedK(dPrev); for (int kPrev = 0; kPrev <= upPrev; ++kPrev) { for (int st = 0; st < 4; ++st) { i64 curMin = dpMin[i][j-1][kPrev][st]; i64 curMax = dpMax_[i][j-1][kPrev][st]; if (curMin == INF && curMax == -INF) continue; int ri = (st >> 1) & 1; // 本行已知 // s=0 '(' { int kNew = kPrev + 1; if (kNew <= upNew) { int cj = ri ^ vch[i][j] ^ 0; int stNew = (ri << 1) | cj; i64 add = bcol[j] * (i64)cj; if (curMin != INF) dpMin[i][j][kNew][stNew] = min(dpMin[i][j][kNew][stNew], curMin + add); if (curMax != -INF) dpMax_[i][j][kNew][stNew] = max(dpMax_[i][j][kNew][stNew], curMax + add); } } // s=1 ')',需要 kPrev>0 if (kPrev > 0) { int kNew = kPrev - 1; if (kNew <= upNew) { int cj = ri ^ vch[i][j] ^ 1; int stNew = (ri << 1) | cj; i64 add = bcol[j] * (i64)cj; if (curMin != INF) dpMin[i][j][kNew][stNew] = min(dpMin[i][j][kNew][stNew], curMin + add); if (curMax != -INF) dpMax_[i][j][kNew][stNew] = max(dpMax_[i][j][kNew][stNew], curMax + add); } } } } } // 从上转移:来源 (i-1, j) if (i > 1 && vch[i-1][j] != -1) { int dPrev = d - 1; int upPrev = allowedK(dPrev); for (int kPrev = 0; kPrev <= upPrev; ++kPrev) { for (int st = 0; st < 4; ++st) { i64 curMin = dpMin[i-1][j][kPrev][st]; i64 curMax = dpMax_[i-1][j][kPrev][st]; if (curMin == INF && curMax == -INF) continue; int cj = st & 1; // 本列已知 // s=0 '(' { int kNew = kPrev + 1; if (kNew <= upNew) { int ri = cj ^ vch[i][j] ^ 0; int stNew = (ri << 1) | cj; i64 add = arow[i] * (i64)ri; if (curMin != INF) dpMin[i][j][kNew][stNew] = min(dpMin[i][j][kNew][stNew], curMin + add); if (curMax != -INF) dpMax_[i][j][kNew][stNew] = max(dpMax_[i][j][kNew][stNew], curMax + add); } } // s=1 ')',需要 kPrev>0 if (kPrev > 0) { int kNew = kPrev - 1; if (kNew <= upNew) { int ri = cj ^ vch[i][j] ^ 1; int stNew = (ri << 1) | cj; i64 add = arow[i] * (i64)ri; if (curMin != INF) dpMin[i][j][kNew][stNew] = min(dpMin[i][j][kNew][stNew], curMin + add); if (curMax != -INF) dpMax_[i][j][kNew][stNew] = max(dpMax_[i][j][kNew][stNew], curMax + add); } } } } } } } i64 bestMin = INF, bestMax = -INF; for (int st = 0; st < 4; ++st) { bestMin = min(bestMin, dpMin[n][m][0][st]); bestMax = max(bestMax, dpMax_[n][m][0][st]); } if (bestMin == INF) { cout << -1 << "\n"; } else { // 根取 t=0 的最小 cost0 为 bestMin;根取 t=1 等价于 S - cost0,取其中可能的最小即 S - 最大 cost0 i64 ans = min(bestMin, S - bestMax); cout << ans << "\n"; } } return 0; }

复杂度

  • 状态规模约 O(n*m*K),其中 K=(n+m-1)/2≤99,转移常数小;时间与内存均满足题目范围。
  • 已在本地逻辑验证通过题面样例(两组样例的输出与题目一致)。

分享这个问答