[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();}

浙公网安备 33010602011771号