随机乱做 Part 7

[CF587F] Duff is Mad(AC 自动机 + 根号分治 + 树状数组)

题面

首先套路地建出 AC 自动机和 fail 树。

考虑如何刻画这个答案:实际上就是所有 \(l\sim r\) 结尾位置的子树内,所包含的串 \(k\) 的节点个数之和。

\(m=\sum|s_i|\)

直接做不太好做,考虑根号分治,设一个阈值 \(B\),则:

  • 对于 \(|s_i|>B\),这种串不会超过 \(\frac{m}{B}\) 个,可以对每个串处理。直接扫一遍 \(k\) 的每个位置,将走到的 fail 树上的位置权值 \(+1\),然后暴力查询子树内节点权值和。可以使用前缀和优化做到 \(\mathcal{O}(\frac{m^2}{B}\times\log m)\)
  • 对于 \(|s_i|\le B\),可以 \(\mathcal{O}(|s_i|)\) 来处理。将询问差分成 \(1\sim r\)\(1\sim l-1\) 两个前缀,然后从 \(1\sim n\) 依次加入字符串。加入的时候,将其结尾节点的子树内的所有节点权值 \(+1\),查询的时候直接把每个走到的位置的权值加起即可。时间复杂度 \(\mathcal{O}(qB\log m)\)

把两种暴力拼起来就行。

代码:https://pastebin.ubuntu.com/p/K8sGf5mHTv/

[CF840E] In a Trap(分块)

题面

先考虑序列上怎么做,即求 \(\max\limits_{i=l}^r\{a_i\oplus (r-i)\}\)。朴素地,把右端点从左往右移动,以某种方式维护答案,把询问挂在右端点上回答。如果每步向后走 \(S\) 步,那么原来维护的 \(a_i\oplus dis\) 就会变成 \(a_i\oplus(dis+S)\)。考虑到异或和加法没有什么优美的性质,所以我们希望能够变成同一种运算。并且由于步长 \(S\) 固定,所以我们可以看成固定右端点 \(r\),向左每 \(S\) 个分一块。

注意到设 \(i\) 到其所在块尾的距离为 \(d_i\),那么 \(a_i\oplus dis=a_i\oplus(d_i+D\times S)\),其中 \(D\)\(i\)\(r\) 之间的块数。并且有 \(0\le dis<S,0\le D\le \frac{n}{S}\)。如果我们把 \(S\) 设成某个 \(2^k\),那么 \(d_i+D\times S=d_i\oplus(D\times S)\)。为了平衡复杂度取 \(S=2^8=256\)

如果我们已经分好了块,那么考虑维护若干个分块类型,记 \(f_{i,j}\) 表示如果已知 \(D=j\),以 \(i\) 为块尾的大小为 \(S\) 的块中最大的 \(a_x\oplus d_x\oplus(D\times S)\)。最大异或这种东西可以想到 Trie 树。因为 \(D\times S\) 的后面 \(8\) 位都是 \(0\),所以可以把 \(a_x\) 的前面 \(8\) 位放到 Trie 树里,并且记录一个 \(mx_y\) 表示 \(a\) 的前面 \(8\) 位是 \(y\) 的时候最大的 \(a\) 后面 \(8\)\(\oplus d\)

化简一下式子,设 \(b_i=\lfloor\frac{a_i}{256}\rfloor,c_i=a_i\bmod 256\),那么 \(a_x\oplus d_x\oplus(D\times S)=((b_x\oplus D)\times S)+(c_x\oplus d_x)\)。将 \(i\) 这一块的所有 \(b\) 放进 Trie 树里,\(mx_y\) 表示 \(b_i=y\) 的所有 \(i\) 中最大的 \(c_i\oplus d_i\)。这个时候可以在 Trie 树中查询异或 \(j\) 得到的最大值来求出 \(f_{i,j}\)。那么固定询问右端点,向左扫每一块,整块答案可以用 \(f\) 数组得到,散块可以暴力。

扩展到树上,只要将每个点向上的 \(S\) 个祖先分到一块就行了。和序列上差不多。

代码:https://paste.ubuntu.com/p/JtHPnxhWcM/

[CF1753D] The Beach(最短路 + 图论建模)

题面

考虑每个位置就是一个点,它表示的意义是这个位置变成空位的最小花费。

那么如果一个位置一开始就是空位,则最小花费是 \(0\)

否则,如果一个位置上有床,那么分类讨论:

  • 如果将床平移,那么这个位置变成空位首先需要床在这个方向上的下一个位置是空位。即如果床在 \((1,1)\)\((1,2)\),那么 \((1,1)\) 变成空位的前提是 \((1,3)\) 变成空位。所以由 床在这个方向上的下一个位置 向这个位置连一条代价为 \(q\) 的单向边。在这个例子里就是 \((1,3)\)\((1,1)\) 连代价为 \(q\) 的单向边。
  • 如果将床旋转,同理,由 这个位置在移动之后变成的位置 向 这个位置 连代价为 \(p\) 的单向边。即如果床在 \((2,2)\)\((1,2)\),那么如果固定 \((2,2)\) 不动,就由 \((2,1)\)\((3,1)\) 分别向 \((1,2)\) 连代价为 \(p\) 的单向边。

从原始空位开始跑多源 Dijkstra,枚举最后床摆放的位置,求出最小代价即可。

代码:https://pastebin.ubuntu.com/p/S77CxkfWh3/

[CF235D] Graph Game(基环树 + 概率期望)

题面

先考虑树的情况怎么做。

由期望的线性性,我们枚举两个点 \((u,v)\),计算 \(u\)\(v\) 的点分树子树中的概率,相加就是期望。

不难发现条件等价于 \(v\)\((u,v)\) 树上路径中最早被选择的点,概率为 \(\frac{1}{dis(u,v)}\)。其中 \(dis(u,v)\)\(u\)\(v\) 路径上的点数。

考虑扩展到基环树。

如果 \(u\)\(v\) 属于同一子树,那么概率还是 \(\frac{1}{dis(u,v)}\)。否则就会有两条路径,考虑容斥,减去多算的部分。设 \(d1\)\(d2\) 分别为两条路径的点数,\(d3\) 为两条路径的并的点数,概率就是 \(\frac{1}{d1}+\frac{1}{d2}-\frac{1}{d3}\)

代码:https://pastebin.ubuntu.com/p/NhQKfNGRxz/

[CF446C] DZY Loves Fibonacci Numbers(线段树 + Fibonacci 数列)

题面

首先需要知道,\(fib_{n+m}=fib_{n+1}fib_m+fib_{n}fib_{m-1}\)

那么就可以有:\(fib_i=fib_{i-1}fib_2+fib_{i-2}fib_1\)

因为在区间内加入一个斐波那契数列,这个区间仍然满足斐波那契数列的关系,所以我们设这个数列为 \(\{a\}\),就有 \(a_i=fib_{i-1}a_{2}+fib_{i-2}a_{1}\)

推导之后还可以得出 \(\sum a_i=fib_na_1+(fib_{n+1}-1)a_2\)

那么对线段树上的区间维护 \(a_1,a_2,sum\) 就行了。

下传标记有点阴间。

代码:https://pastebin.ubuntu.com/p/wnFnBrP9Pg/

[CF309E] Sheep(二分 + 贪心)

题面

最大值最小,想到二分。

考虑从 \(1\sim n\) 依次确定每个位置填哪一个区间。维护每个区间能放的最远位置 \(mx_i\),记 \(cnt_j\) 表示 \(mx_i\le j\)\(i\) 的个数。假设现在填到了位置 \(x\),那么无解当且仅当存在一个 \(cnt_j>j-x+1\)(这就是说这个区间不够填了)。否则找到最小的 \(j\) 满足 \(cnt_j=j-x+1\),将满足 \(mx<j\) 的右端点最小的区间填到这里。

贪心正确性见 https://www.cnblogs.com/PYWBKTDA/p/16458642.html。感性理解就是尽量减少相交的数量。

代码:https://pastebin.ubuntu.com/p/Q6JwFs3tmx/

[POI2012] OKR-A Horrible Poem(字符串哈希 + 周期串的性质)

题面

  • 如果 \(len\) 是一个串的循环节,并且 \(k\times len\) 是串长的约数,那么 \(k\times len\) 也一定是这个串的循环节。

  • \(s_{l,r}\) 有一个长度为 \(len\) 的循环节的充要条件就是 \(s_{l,r-len}=s_{l+len,r}\)

上面这两条性质很好证。

那么暴力怎么做?可以枚举区间长度的约数然后哈希判断。

考虑优化一下这个过程。记录 \(mn_x\) 表示 \(x\) 的最小质因子,那么每次我们把 \(len\leftarrow \frac{len}{mn_{len}}\),然后再判断是否仍然是循环节。

代码:https://pastebin.ubuntu.com/p/Mczpn4wg4M/

posted @ 2022-11-01 20:31  csxsi  阅读(7)  评论(0编辑  收藏  举报