【题解】CSP2019-Day1
20191116-CSP2019-Day1
CSP-J
code
学习了下格雷码……挺简单的,只是考了unsigned long long
的使用有点不太友好……
据说有一个结论:答案为(k^(k>>1))
。……就是一个归纳。
设\(f(x)\)表示\(x\)的除去前导零后格雷码的值,\(\oplus\)代表异或运算,对\(x\in\{0,1\}\),\(!x=x\oplus 1\),则由格雷码的递归定义有:
\[f(0)=0=0\oplus(0/2) \\
\begin{aligned}
f((1b_{n-1}\cdots b_0)_2) &= 2^n+f(2^n-1-(b_{n-1}\cdots b_0)) \\
&= 2^n+f((!b_{n-1}\cdots !b_0)_2) \\
&= 2^n+((!b_{n-1}\cdots !b_0)_2\oplus (!b_{n-1}\cdots !b_1)_2) \\
&= ((1)(1 \oplus b_{n-1})(b_{n-1}\oplus b_{n-2})\cdots (b_0\oplus b_1))_2
\end{aligned}
\]
brackets
注意到如果你DFS
这棵树,相当于对一个序列执行
- 在末尾加/删除字符
- 计算增加/减少的合法括号子串
原问题就简化成了一个一维的问题。
设val['(']=1,val[')']=-1
,\(s_i=\sum_{j=1}^ival[s[i]]]\)则操作2等价于对右端点\(l\)求
\[\sum_{i=0}^l[s_i=s_l][\min_{i\le j\le l}s_j=s_l]
\]
由于\(\min_{i\le j\le l}s_j\)一项单调,考虑对一个节点\(i\)维护:
pre[i]
,即\(s\)值小于\(s_i\)的\(i\)的最深祖先,若不存在则为0
。- 若
s[i]==')'
,则\(s_i<s_j\),pre[i]=pre[pre[fa[i]]
。 - 若
s[i]=='('
,则\(s_i>s_j\),pre[i]=fa[i]
。
- 若
same[i]
,即有\(\sum_{j=pre_i}^i[s_j=s_i]\)的值。- 仿上维护即可。
最后,注意用long long
存答案。(虽然样例3的输出良心地提示了这一点)
tree
这题略微有点毒瘤……两个小时都没能调出来,爆零……(其实是因为忘记可以写暴力+对拍了……比赛经验太少)
手玩样例发现,如果将一个值\(i\)从\(u=p_i\)换到\(v\),假设经过的节点分别为\(p_0=u,p_1,\cdots,p_l=v\),对边的限制有:
- \((p_0,p_1)\)这条边为\(p_0\)的第一个被删除的边。
- 对于\(p_i\),\((p_i,p_{i+1})\)这条边应该在\((p_{i-1},p_i)\)这条边之后立刻删除。
- \((p_{l-1},p_l)\)这条边为\(p_l\)的最后一个被删除的边。
注意到,这些限制都可以用链表维护。(对每一个节点开一个链表)
最后只需要枚举p[i]
,通过DFS
的到可以换到的编号最小的节点,再进行修改即可。
值得注意的是,这题细节很多,一不小心就会WA
到自闭。(反正我考场上没有调出来)
最后的最后总算调出来了……主要问题是每个节点维护的边的链表有很多种特殊情况没有判断,在访问链表的元素前做一些很烦人的判断保证不会出现非法操作即可。