• 蓝桥杯每日一题2023.10.5


    3420. 括号序列 - AcWing题库

    题目描述

    题目分析 

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

    完全背包的朴素写法:

    1. #include
    2. using namespace std;
    3. const int N = 1010;
    4. int n, m, v[N], w[N], f[N][N];
    5. int main()
    6. {
    7. cin >> n >> m;
    8. for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i];
    9. for(int i = 1; i <= n; i ++)
    10. {
    11. for(int j = 0; j <= m; j ++)
    12. {
    13. for(int k = 0; k * v[i] <= j; k ++)
    14. {
    15. f[i][j] = max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);
    16. }
    17. }
    18. }
    19. cout << f[n][m] << '\n';
    20. return 0;
    21. }

    经行优化:

    f[i][j] = f[i - 1][j - v[i] * k] + w[i] * k
    f[i][j] = max(f[i - 1][j], f[i - 1][j - v] + w, f[i - 1][j - 2v] + 2w, f[i - 1][j - 3v] + 3w, ...)
    f[i][j - v] = max(         f[i - 1][j - v],       f[i - 1][j - 2v] + w,    f[i - 1][j - 3v] + 2w, ...)
    f[i][j] = max(f[i - 1][j], f[i][j - v] + w)

    1. #include
    2. using namespace std;
    3. const int N = 1010;
    4. int n, m, v[N], w[N], f[N][N];
    5. int main()
    6. {
    7. cin >> n >> m;
    8. for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i];
    9. for(int i = 1; i <= n; i ++)
    10. {
    11. for(int j = 0; j <= m; j ++)
    12. {
    13. for(int k = 0; k * v[i] <= j; k ++)
    14. {
    15. f[i][j] = f[i - 1][j];
    16. if(j >= v[i])f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
    17. }
    18. }
    19. }
    20. cout << f[n][m] << '\n';
    21. return 0;
    22. }

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

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

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

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

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

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

    1. #include
    2. using namespace std;
    3. typedef long long ll;
    4. const int N = 5010, mod = 1e9 + 7;
    5. char s[N];
    6. int n;
    7. ll f[N][N];
    8. ll work()
    9. {
    10. memset(f, 0, sizeof f);
    11. f[0][0] = 1;
    12. for(int i = 1; i <= n; i ++)
    13. {
    14. if(s[i] == '(')
    15. {
    16. for(int j = 1; j <= n; j ++)f[i][j] = f[i - 1][j - 1];
    17. }
    18. else
    19. {
    20. f[i][0] = (f[i - 1][0] + f[i - 1][1]) % mod;
    21. for(int j = 1; j <= n; j ++)f[i][j] = (f[i - 1][j + 1] + f[i][j - 1]) % mod;
    22. }
    23. }
    24. for(int i = 0; i <= n; i ++)
    25. {
    26. if(f[n][i])return f[n][i];
    27. }
    28. return -1;
    29. }
    30. int main()
    31. {
    32. cin >> s + 1;
    33. n = strlen(s + 1);
    34. ll l = work();
    35. reverse(s + 1, s + n + 1);
    36. for(int i = 1; i <= n; i ++)
    37. {
    38. if(s[i] == '(')s[i] = ')';
    39. else s[i] = '(';
    40. }
    41. ll r = work();
    42. cout << l * r % mod;
    43. return 0;
    44. }
  • 相关阅读:
    Linux项目自动化构建工具-make/Makefile
    C++如何查看栈的变量
    一个SpringBoot单体项目--》瑞吉外卖项目之后台管理端基础功能开发
    红黑树(四) - C++实现
    Linux Ubunto Nginx安装
    终极篇章1——(16000字)SpringBoot启动原理分析(第一部分)
    人脸识别技术趋势与发展
    Canal使用
    15:00面试,15:06就出来了,问的问题有点变态。。。
    C语言文件操作(详解)
  • 原文地址:https://blog.csdn.net/m0_75087931/article/details/133584841