智乃的括号匹配
智乃的括号匹配
题目描述
智乃现在有一个仅由 "(" 和 ")" 组成长度大小为 的字符串,字符串的每一个位置的字符都有自己的权值 和代价 。
智乃定义一对在该字符串中配对的括号对,假设左括号的坐标为 ,右括号为 ,该括号对的价值为两个括号权值的乘积 。
"配对的括号"指从右往左开始对于每一个 '(',从它开始向右找到第一个未配对的 ')' 组成一对配对的括号。例如在 "(())" 中,假设下标分别为 首先找到 位置的 '(' 与 的 ')' 进行配对,接下来 位置的 '(' 由于 已经配对,所以最终 和 配对。
智乃定义整个字符串的价值为所有配对的括号对价值之和,注意并不要求整个字符串都是配对的。
现在对于任意下标为 的括号,智乃可以消耗它的代价 将其翻转,即 "(" 变为 ")",")" 变为 "("。
假设智乃的最总得分为经过若干次操作后,字符串的价值减去操作的代价之和,求智乃的最大得分。
注意当字符串价值小于操作的代价和时,智乃的得分可能是负数。
输入描述:
第一行输入一个正整数 表示字符串的大小。
接下来输入一个长度大小为 的字符串 。
接下来输入 个正整数 表示字符串每个字符的权值。
接下来输入 个正整数 表示字符串每个字符的代价。
输出描述:
仅一行一个整数,表示最大得分。
示例1
输入
2
)(
4 3
10 10
输出
0
说明
如果将两个括号都翻转,则代价为 20,收益为 12,这样倒亏 8,不如什么都不做。
示例2
输入
2
((
4 3
10 10
输出
2
说明
翻转第二个括号,则代价为 10,收益为 12,最大得分为 2。
示例3
输入
4
()()
-1 100 10 10
1000 101 100 100
输出
789
说明
最优操作位变成 "(())"。得分 990,代价为 201。
示例4
输入
2
()
-1 100
10 10
输出
-10
说明
如果放着不动,会直接亏 100,不如翻转一下主动亏 10
解题思路
官方题解写的什么鬼,完全看不懂。
注意到当把所有成对匹配的括号删去,那么剩余元素必然是 )...))((...(
的形式,即左部分全是 )
(或空集),右部分全是 (
(或空集)。把分界点记作 ,显然原序列的 中的 (
只会与 中的 )
匹配。同理原序列的 中的 )
只会与 中的 (
匹配。所以当分界点 确定后左右两部分是独立的。
为此定义 表示将 中的 (
进行匹配使剩余元素均为 )
(或空集)所能获得的最大得分,定义 表示将 中的 )
进行匹配使剩余元素均为 (
(或空集)所能获得的最大分数。
考虑如何通过 转移得到 。如果 不会被匹配,那么就需要把 的 (
匹配掉,再让 变成 )
,转移方程就有 。这里的 表示将 变成 (
或 )
的代价( 或 )。否则如果 与 匹配,那么就需要把 的括号都匹配完(显然 应该为偶数),再让 变 (
变 )
。先定义 表示将 (长度为偶数)都匹配完所能获得的最大分数。因此转移方程就是 。
综上有
同理考虑从 转移到 ,转移方程为
而 就是一个区间 dp。如果 和 匹配,那么转移方程就是 。否则由于 都要匹配完,枚举 ,分别将 和 匹配完,转移方程就是 。
最后答案就是 。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 505;
char s[N];
int v[N], c[N], w[N][2];
LL f[N][N], l[N], r[N];
int main() {
int n;
scanf("%d %s", &n, s + 1);
for (int i = 1; i <= n; i++) {
scanf("%d", v + i);
}
for (int i = 1; i <= n; i++) {
scanf("%d", c + i);
if (s[i] == '(') w[i][1] = -c[i];
else w[i][0] = -c[i];
}
for (int len = 2; len <= n; len += 2) {
for (int i = 1; i + len - 1 <= n; i++) {
int j = i + len - 1;
f[i][j] = f[i + 1][j - 1] + w[i][0] + w[j][1] + 1ll * v[i] * v[j];
for (int k = i + 1; k + 1 < j; k += 2) {
f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j]);
}
}
}
for (int i = 1; i <= n; i++) {
l[i] = l[i - 1] + w[i][1];
for (int j = i - 1; j >= 1; j -= 2) {
l[i] = max(l[i], l[j - 1] + f[j + 1][i - 1] + w[j][0] + w[i][1] + 1ll * v[j] * v[i]);
}
}
for (int i = n; i; i--) {
r[i] = r[i + 1] + w[i][0];
for (int j = i + 1; j <= n; j += 2) {
r[i] = max(r[i], r[j + 1] + f[i + 1][j - 1] + w[i][0] + w[j][1] + 1ll * v[i] * v[j]);
}
}
LL ret = -1e18;
for (int i = 0; i <= n; i++) {
ret = max(ret, l[i] + r[i + 1]);
}
printf("%lld", ret);
return 0;
}
参考资料
【题解】牛客练习赛124_PLUS:https://ac.nowcoder.com/discuss/1298659
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18162323
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2023-04-27 闇の連鎖