CTS(C) 乱做

一些简单的题就不写了,一些过的人极少的题也不写了,之前写过的也不写了。

以下大部分仍然都是口胡。

LOJ2262. 「CTSC2017」网络

先把直径拉出来。

考虑连边的两个点,画画图大力讨论一下可以发现这两个点都一定要在直径上。

所以先把直径上每个点的子树内的最长路考虑掉,然后每棵子树就只需要考虑最深深度了。并且连边的两个点也可以被抽象成左端点 \(l\) 和右端点 \(r\)

二分答案。

对于确定的左右端点,可能构成最长路的有几种:比 \(l\) 更左的点对;比 \(r\) 更右的点对;一个是直径左端点,一个是 \([l,r]\) 之间的点;一个是直径右端点,一个是 \([l,r]\) 之间的点;都是 \([l,r]\) 之间的点;直径端点。

第一种和第二种分别对 \(l,r\) 的取值做了区间限制。

对于第三种,随着 \(l\) 往右,\(r\) 就必须往左,并且可以用前缀最值来判断。第四种和第三种对称。

对于第五种,随着 \(l\) 往右,\(r\) 也可以往右,所以可以双指针+单调队列。

第六种非常简单。

最终复杂度 \(O(n\log v)\) 。然后出来一看发现正解非常清晰且简单,于是当场暴毙……

正解:把绝对值的式子列出来,根据绝对值的性质拆掉并分类讨论正负性,然后搞搞搞。

LOJ2263. 「CTSC2017」游戏

概率不会,菜鸡落泪

但是这题其实不需要太多概率的知识。根据直觉,答案是可以这么算的:枚举每一种合法的输赢情况,算出它的次数乘概率,求和,最后除以总概率。

事实可以证明这样做是对的,感觉也很没有毛病。

于是容易写个 DP ,也容易把它改成矩乘,线段树维护一下即可。

LOJ2553. 「CTSC2018」暴力写挂

先考虑边权为正怎么做。

在第二棵树上枚举 lca ,然后考虑 \(dep_x+dep_y-dep_{lca(x,y)}\) 怎么处理。

发现可以在原树上的每个点 \(u\) 挂上一个点 \(u'\) ,边权为 \(dep_u\) ,然后再把边权全部除 2 ,这样上面的式子就变成 \(dis(x',y')\) 了。

于是利用直径的性质容易在第二棵树上合并两棵子树并统计答案。

但是边权为负的时候直径的很多性质就无了,就比较难做了。

有一个树剖+启发式合并的做法,不过是 \(O(n\log^3 n)\) 的,并且没有用到距离的转化。

既然是距离那么可以动态点分治,然后同样启发式合并,就 \(O(n\log^2 n)\) 了。

通过阅读题解发现可以不做这个转化,而是化成 \(dis(x,y)+dep_x+dep_y\) ,然后边分治合并(类似线段树合并)做到一个 \(\log\) 。不过这个做法自然也可以边分治做到一个 \(\log\)

点分治的问题就在于一个点的儿子太多,用线段树合并的写法应该复杂度是假的,只能启发式合并。

LOJ2554. 「CTSC2018」青蕈领主

由于连续段的性质,任意两个题目给出的线段要么包含要么不交,所以可以建出一棵树。

在树上,如果一个点有 \(k\) 个儿子,那么把每个儿子代表的连续段缩成一个点,自己也是一个点,那么方案数就是 \(f_{k}\) ,其中 \(f_n\) 表示 \(n+1\) 个点的排列,不存在不包含 \(p_{n+1}\) 的长度至少为 2 的连续段,的方案数。

现在的问题就是如何求出 \(f\)

不包含 \(p_{n+1}\) 可以等价为不包含 \(n+1\) 。把数从大到小插入,考虑 1 的位置。

如果在插入 1 之前这个排列已经满足条件,那么 1 只要不和 2 相邻即可,方案数是 \((n-1)f_{n-1}\)

否则,所有不合法的连续段(指长度不为 1 且不包含 \(n+1\) )必须两两有交。考虑最长的那个连续段,它必然是所有不合法的连续段的并。现在要把 1 插入并使得合法。

枚举这个段的长度是 \(j\) 。考虑段内有哪些元素,显然不能有 2 和 \(n+1\) ,所以有 \(n-j-1\) 种选择。

此时加入 1 ,可以看做加入了 \(mx+1\) ,并要求所有长度不为 1 的连续段都包含 \(mx+1\) ,所以段内的方案数是 \(f_j\)

加入 1 之前,可以把这个段合成一个点,然后要求排列合法。这个方案数是 \(f_{n-j}\)

于是得到式子 \(f_n=(n-1)f_{n-1}+\sum_{j=2}^{n-2} (n-j-1)f_jf_{n-j}\) ,分治 FFT 优化即可。

感觉很妙,想不到呀 /kk

LOJ3123. 「CTS2019 | CTSC2019」重复

不会 kmp ,告辞

太棒了,学到许多

由于句子是不确定的,所以在句子上跑 kmp 或最小表示法的想法不太能做。

因此选择给 \(s\) 建 kmp 自动机,考虑如何把一个 \(t\) 放在上面跑,以此判断是否合法。

这个是可以做到的:把 \(t\) 放在自动机上面跑,唯一不同的地方是加入一个字符 \(c\) 时,如果当前位置的 fail 树上的祖先存在一个点的下一个位置大于 \(c\) ,那么直接返回合法。

所以可以想到统计不合法串的个数。

此时自动机长这样:对于一个点,存在一个字符 \(c\) ,使得喂进来的字符是 \(c\) 时会指向一个位置,大于 \(c\) 时指向原点,小于 \(c\) 的转移不存在。注意这个自动机就是 kmp 自动机挖掉一些转移,所以还是具有 kmp 自动机的性质。

然后是一个玄妙的(我想不到的)结论:一个不合法串如果循环足够多次后会走到 \(pos\) ,那么再循环一次还会回到 \(pos\) ,并且走出的 \((circle,pos)\) 二元组是和不合法串一一对应的。

为什么?

显然一个串是可以对应到一个 \((circle,pos)\) 上的:循环了足够大的 \(k\) 次时后缀能匹配到 \(pos\) ,那么再加一次就不可能得到更大或更小的 \(pos\)

而一个 \(circle\) 可以对应到一个串,只需要证明这个串循环足够多次后能走到 \(pos\)

这也可以证明:如果 \(pos\le m\) ,那么循环一次就可以走到 \(pos\) ;否则,由于 \(lcs(s[1,pos],s[1,pos]+t)=s[1,pos]\) ,可以得到 \(t\)\(s[1,pos]\) 的循环节。

所以问题就转化为数这样的二元组的个数。

注意到不指向原点的出边每个点只有一个,所以没有经过原点的二元组很好求。经过原点的可以求出 \(dp_{i,j}\) 表示从原点走 \(i\) 步走到 \(j\) 的方案数,然后枚举 \(pos\) ,枚举走了几步才第一次走到原点,然后用 DP 数组计算答案。

复杂度 \(O(nm)\)

为什么都觉得这是道简单题呀 /kk

posted @ 2020-09-08 17:27  p_b_p_b  阅读(425)  评论(0编辑  收藏  举报