蓝桥杯每日一题2023.10.5

3420. 括号序列 - AcWing题库

题目描述

题目分析

对于这一我们需要有前缀知识完全背包

完全背包的朴素写法:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m, v[N], w[N], f[N][N];
int main()
{
	cin >> n >> m;
	for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i];
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 0; j <= m; j ++)
		{
			for(int k = 0; k * v[i] <= j; k ++)
			{
				f[i][j] = max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);
			}
		}
	}
	cout << f[n][m] << '\n';
	return 0;
}

经行优化:

fij = fi - 1j - v\[i * k] + wi * k

fij = max(fi - 1j, fi - 1j - v + w, fi - 1j - 2v + 2w, fi - 1j - 3v + 3w, ...)

fij - v = max( fi - 1j - v, fi - 1j - 2v + w, fi - 1j - 3v + 2w, ...)

fij = max(fi - 1j, fij - v + w)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m, v[N], w[N], f[N][N];
int main()
{
	cin >> n >> m;
	for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i];
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 0; j <= m; j ++)
		{
			for(int k = 0; k * v[i] <= j; k ++)
			{
				f[i][j] = f[i - 1][j];
				if(j >= v[i])f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
			}
		}
	}
	cout << f[n][m] << '\n';
	return 0;
}

首先由题意知我们左右括号的数量必须相等,对于任意前缀的左括号的数量必须大于等于有括号的数量(如果小于则此处必定需要添加括号)

我们可以分为两种方案使其独立存在,一种是只添加左括号,一种是只添加右括号,这两种方案各进行一次,将方案数相乘则为总方案数,对于左右进行的操作只需用同一代码即可,我们可以只写对左括号进行操作,对于右括号操作我们只需要将字符串翻转即可实现操作

使用动态规划来记录方案数

fij :只考虑前i部分,左括号比右括号多j 个的所有方案的集合(不同数量的左括号的方案数)

1.若si == '(' fij = fi - 1j - 1(考虑前i - 1部分时,左括号数量比右括号数量多j - 1个,那么第i部分左括号就比右括号多j个)

2.若si == ')' fij = fi - 1j + 1 + fi - 1j + ... + fi - 10(考虑前i - 1部分左括号数量最多比右括号数量多j + 1个,才能在第i部分通过添加或者不加左括号使左括号的数量比右括号的数量多j个)注:这里类似于完全背包的优化:fij = fi - 1j + 1 + fij - 1,考虑越界问题,fi0特判(j == 0,j - 1 = -1越界)fi0可以考虑前i - 1部分左括号数和右括号数相等 和 左括号数比右括号数多一个的和

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5010, mod = 1e9 + 7;
char s[N];
int n;
ll f[N][N];
ll work()
{
	memset(f, 0, sizeof f);
	f[0][0] = 1;
	for(int i = 1; i <= n; i ++)
	{
		if(s[i] == '(')
		{
			for(int j = 1; j <= n; j ++)f[i][j] = f[i - 1][j - 1];
		}
		else
		{
			f[i][0] = (f[i - 1][0] + f[i - 1][1]) % mod;
			for(int j = 1; j <= n; j ++)f[i][j] = (f[i - 1][j + 1] + f[i][j - 1]) % mod;
		}
	}
	for(int i = 0; i <= n; i ++)
	{
		if(f[n][i])return f[n][i];
	}
	return -1;
}
int main()
{
	cin >> s + 1;
	n = strlen(s + 1);
	ll l = work();
	reverse(s + 1, s + n + 1);
	for(int i = 1; i <= n; i ++)
	{
		if(s[i] == '(')s[i] = ')';
		else s[i] = '(';
	}
	ll r = work();
	cout << l * r % mod;
	return 0;
}
相关推荐
十二6 分钟前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
小此方1 小时前
[算法实战论:动态规划]回文串问题的dp解法,回文串问题的母题,以及以此为基础的派生题
算法·动态规划
Pniubi2 小时前
力扣560.和为k的子数组
算法·leetcode·职场和发展
D e re k ZH2 小时前
C++ 从零入门(一):基础语法与程序结构
数据结构·c++·算法
Pniubi3 小时前
力扣438.找到字符串中所有字母异位词
算法·leetcode·职场和发展
東隅已逝,桑榆非晚5 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
Eyfcom5 小时前
〖物联网终端实战 01〗UWB 室内高精度定位:仓储 AGV 与人员的厘米级轨迹追踪
物联网·算法·物流系统·快递系统·跨境物流快递系统·物联网终端实战
bro_Java6666 小时前
《排序的底层逻辑:比较、交换与分治》
java·算法·排序算法
爱喝雪碧的可乐6 小时前
MATLAB
开发语言·算法·matlab
叼烟扛炮7 小时前
Linux 学习笔记(六十):单线程的逆袭——epoll 高并发服务器实战
linux·服务器·网络·笔记·学习·算法