[CSP 2019]括号树[dp]

原题:https://www.luogu.com.cn/problem/P5658

好菜啊这么久才把这道 签到题 补掉....


考场上只会一个 $O(n^2)$ 暴力,考虑把暴力换成 dp

首先一定有一个 $dp_i$ 表示当前位置的答案,显然无法直接转移,考虑还需要知道哪些信息?

还需要记一个 $lst_i$ 表示当前位置 ')' 能匹配到的 '(' 的位置

为了统计答案还需要一个 $now_i$ 表示当前位置向根 连续 的合法括号串的数量

大概可以了,来考虑一下如何转移,首先一定需要分类讨论

如果是 '(' ,那么似乎没有什么可做的,继承了父亲的答案数组 f ,然后把 $lst_i$ 设为自己即可

如果是 ')' ,且 $lst_i == 0$,这个括号是没有用处的,继承父亲的答案数组 f 然后跑就完事了

如果是 ')' ,且 $lst_i$ 有值,那么首先 f 和 lst 继承以下父亲,然后三个数组都需要有以下转移

$now_i=now[fa[lst_i]] + 1$,连续的合法串又多了一个

$f_i = f[fa[i]] + now_i$,答案可以统计出来了

$lst_i=lst[fa[lst_i]]$,待匹配的 '(' 向上方移动一个

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 #include <vector>
 7 #include <queue>
 8 #include <cctype>
 9 #define inf 500010
10 #define ll long long
11 
12 namespace chiaro {
13 
14 template <class T>
15 inline void read(T& num) {
16     num = 0; register char c = getchar(), up = c; while(!isdigit(c)) up = c, c = getchar();
17     while(isdigit(c)) num = (num * 10) + c - '0', c = getchar(); up == '-' ? num = -num : 0;
18 }
19 
20 inline void setting() {
21 #ifdef ONLINE_JUDGE
22     freopen("brackets.in", "r", stdin);
23     freopen("brackets.out", "w", stdout);
24 #endif
25 }
26 
27 int fa[inf];
28 ll ans;
29 int n;
30 char str[inf];
31 ll f[inf];
32 int now[inf];
33 int lst[inf];
34 
35 inline int main () {
36     setting();
37     read(n);
38     scanf("%s", str + 1);
39     for(register int i = 2; i <= n; i++) read(fa[i]);
40     for(register int x = 1; x <= n; x++) {
41         f[x] = f[fa[x]];
42         lst[x] = lst[fa[x]];
43         if(str[x] == '(') {lst[x] = x;continue;}
44         if(lst[x] == 0) {lst[x] = 0; continue;}
45         now[x] = now[fa[lst[x]]] + 1;
46         f[x] = f[fa[x]] + now[x];
47         lst[x] = lst[fa[lst[x]]];
48     }
49     for(register int i = 1; i <= n; i++) ans ^= i * f[i];
50     printf("%lld\n", ans);
51     return 0;
52 }
53 
54 }
55 
56 signed main() {return chiaro::main();}

 

posted @ 2020-08-25 19:23  Chiaro  阅读(151)  评论(0)    收藏  举报