【题解】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这棵树,相当于对一个序列执行

  1. 在末尾加/删除字符
  2. 计算增加/减少的合法括号子串

原问题就简化成了一个一维的问题。

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\)维护:

  1. 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]
  2. 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\),对边的限制有:

  1. \((p_0,p_1)\)这条边为\(p_0\)的第一个被删除的边。
  2. 对于\(p_i\)\((p_i,p_{i+1})\)这条边应该在\((p_{i-1},p_i)\)这条边之后立刻删除。
  3. \((p_{l-1},p_l)\)这条边为\(p_l\)的最后一个被删除的边。

注意到,这些限制都可以用链表维护。(对每一个节点开一个链表)

最后只需要枚举p[i],通过DFS的到可以换到的编号最小的节点,再进行修改即可。

值得注意的是,这题细节很多,一不小心就会WA到自闭。(反正我考场上没有调出来)


最后的最后总算调出来了……主要问题是每个节点维护的边的链表有很多种特殊情况没有判断,在访问链表的元素前做一些很烦人的判断保证不会出现非法操作即可。

posted @ 2021-05-20 20:59  frank3215  阅读(59)  评论(0编辑  收藏  举报