zoukankan      html  css  js  c++  java
  • 洛谷P5658 括号树(CSP-S 2019 D1T2)题解 动态规划

    题目链接:https://www.luogu.com.cn/problem/P5658

    解题思路:

    我们不妨将这道题进行一下简化,变成如下题目描述:

    给你一个字符串,求这个字符串中有多少合法括号子串,看看能不能在O(n)时间复杂度内解决这个问题。

    对于这样一个问题,我们可以用栈存储所有没有匹配上的 ‘(’ 对应的坐标,然后用数组 match[i] 表示当前位置 i 对应的刚好匹配上的左括号的坐标(当然前提是栈中有元素且当前元素 s[i] == ')')。
    然后我们用 sum[i] 表示以 s[i] 结尾的合法括号子串的数量,则:如果 match[i] != 0sum[i] = sum[match[i]-1] + 1
    答案就是 (sum{sum[i]})
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1000010;
    stack<int> stk;
    int match[maxn];
    char s[maxn];
    long long sum[maxn], ans;
    int main() {
        scanf("%s", s+1);
        int n = strlen(s+1);
        for (int i = 1; i <= n; i ++) {
            if (s[i] == '(') stk.push(i);
            else {
                if (!stk.empty()) {
                    int p = stk.top();
                    stk.pop();
                    sum[i] = sum[p-1] + 1;
                }
            }
        }
        for (int i = 1; i <= n; i ++) ans += sum[i];
        printf("%lld
    ", ans);
        return 0;
    }
    

    同样的思路,放到树上,只要在dfs的过程中进行同样的处理即可。

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1000010;
    int n, match[maxn], stk[maxn], sp[maxn], f[maxn], sz;
    long long sum[maxn], tot[maxn], ans;
    char s[maxn];
    vector<int> g[maxn];
    void dfs(int u, int id) {
        if (s[u] == '(') {
            sp[u] = id;
            id = u;
        }
        else {
            if (id) {
                match[u] = id;
                sum[u] = 1 + sum[f[match[u]]];
                id = sp[id];
            }
        }
        tot[u] = tot[f[u]] + sum[u];
        int sz = g[u].size();
        for (int i = 0; i < sz; i ++) {
            int v = g[u][i];
            dfs(v, id);
        }
    }
    int main() {
        scanf("%d%s", &n, s+1);
        for (int i = 2; i <= n; i ++) {
            scanf("%d", f+i);
            g[ f[i] ].push_back(i);
        }
        dfs(1, 0);
        for (int i = 1; i <= n; i ++)
            ans ^= (long long) i * tot[i];
        printf("%lld
    ", ans);
        return 0;
    }
    

    当然这里处理的时候要注意一些细节,其中最不方便思考的一个问题是:栈如何保存。

    所以这里我单独开了一个 (sp[i]) 用于表示在 (i) 刚添加进栈的时刻之前栈顶元素的坐标。

    (sum[i]) 表示的还是以 (s[i]) 结尾的合法括号串数量。

    (tot[i]) 表示的是根节点到 (i) 号节点的所有点的 (sum) 值之和。

    最终的答案就是所有的 (i imes tot[i]) 的异或和。

    当然这里还需要注意一点就是其实我的 (match[]) 数组可以不开,但是开着方便理解,所以我就没有去掉了。

  • 相关阅读:
    Liunx基础优化配置
    Linux配置国内的Yum源
    Liunx配置静态IP
    百度前端学院|任务七
    java的远程访问接口的实例
    java套接字实现接口访问
    Mysql的链接超时异常CommunicationsException
    mysql查看和设置timeout 和批量杀死链接进程
    springmvc接受表单多条数据的值
    jquery获取点击标签内的子标签内容和值实例
  • 原文地址:https://www.cnblogs.com/quanjun/p/13131991.html
Copyright © 2011-2022 走看看