Atcoder 题目选做

ABC257 G

直接考虑 \(\rm KMP\) 的过程。\(\rm KMP\) 可以帮助我们求出 \(S\)\(border\) ,并找到 \(T\) 中每一个位置能匹配上的 \(S\) 的最长前缀。

那么我们就可以很轻松的在 \(T\) 的每一个位置找到他能匹配到的 \(S\) 的前缀。由此,我们在 \(T\) 上做 \(DP\) ,令 \(dp_i\) 表示考虑到 \(T\) 的第 \(i\) 个字符,到这个位置需要的 \(S\) 的最小前缀数。

但是直接这样做 \(DP\) ,复杂度最坏还是 \(O(n^2)\) 的,所以我要做一点小优化。考虑我们在给 \(T\) 匹配 \(S\) 前缀的过程,我们如果直接有 \(s_{j+1}=t_i\) ,而没有经过跳 \(\pi\) 的过程,那我们可以直接从 \(i-1\) 转移答案。具体的,当这个时候 \(j=0\) ,那么 \(dp_i=dp_{i-1}+1\) ,否则 \(dp_i=dp_{i-1}\) 。这样子,复杂度最坏是 \(O(n\log n)\)

代码:Link

ARC149 D

又是切不动的 700 题。

首先,我们考虑所有在 \([1,10^6]\) 的点经过 \(M\) 次操作后的情况。

其次通过观察可以得知 \(x\)\(-x\) 在经过相同的一系列操作后,只要中间没有到过 \(0\) ,最后结束位置也是对称的。(性质 \(A\) )

那么,每经过一次操作,我们都可以吧当前的整段序列看作 3 个部分:1.正数 2.0 3.负数 。又因为上面的性质 \(A\) ,我们在这之后只用考虑 正数 和 负数 中一个即可,另一部分完全可以推出来。

首先我们肯定会选择正数 和 负数 中数量多的那一部分,为了更好的在最后得到少的那一部分的答案,我们考虑对于少的那一部分的每一个编号连一条边,连到另一部分的它所对应的编号那里去。然后就不再考虑少的那一部分的情况了。

这样做到最后我们就得到了一颗森林(编号组成的),我们遍历每一棵树,如果这棵树的根在中间到达过 \(0\) ,那么这棵树的所有结点的编号都会在那个时间点到达 \(0\) 。如果没有到达过 \(0\) ,那么没经过一条边,最终的位置的下标就会取反一次。

这样子就可以得到所有 \([1,10^6]\) 之内的数的结果了。

具体实现的话,没有必要真的做 \([1,10^6]\) ,找到最大值即可。同时可以维护四个指针 \(l,r,L,R\) ,分别表示当前的编号区间和下标区间,这样子在做每次操作的时候,就好维护剩下的区间和连边了。

复杂度:\(\mathcal O(M+\max{X_i})\)

代码:Link

最后放一张官方题解的解释图。

放一张官方题解的解释图

ARC149 E

神仙题/bx

首先题面里又是下标取模,又是重排序,看着很难受。不妨转化一下题面。

给定一个序列 \(A\) 。进行以下操作 \(K\) 次。

  • \((A_0,A_1,...A_{M-1})\) 从小到大排序
  • 把整个序列 \(A\) 向左循环平移一位。

以样例为例:\((4,1,5,6,2,3)\rightarrow (4,5,6,2,3,1)\rightarrow (5,6,2,3,1,4)\rightarrow(5,6,3,1,4,2)\rightarrow (5,6,1,4,2,3)\rightarrow (5,6,4,2,3,1)\)

相应的 \(B\) 序列也要做一下处理,把 \(B\) 数组整体向左循环平移 \(K\%N\) 次。

然后观察整个过程,可以发现最左边的 \(M-1\) 项在经过至少一次操作后,永远是升序的。那么我们可以把最左边的这 \(M-1\) 项看作左部,右边的 \(N-M+1\) 项看作右部。令左部有 \(L\) 个数,右部有 \(R\) 个数。

我们可以再次简化我们的操作。(左部最后一定是升序的)。

维护左部和右部。每次把右部最前面的数加进左部,左部再把最小的数加到右部的末尾。

进一步观察我们的操作。

可以发现,如果 \(R>K\) ,那么其实只有最开始的前 \(K\) 个右部数会进入左部进行比较,后面的数相对位置不会有任何改变,也不会参与任何比较。我们可以直接扔掉那些没有的数。

如果 \(R<K\) 。那么在进行 \(R\) 次之后,左部一定是 \(\{R+1,R+2,...N\}\) ,右部的数只要进去就一定会被扔出来。从结果上来看左部没有变,右部每次向左循环位移一位。

经过以上分析,我们发现我们总能把问题规约为 \(R=K\) 的情况,然后我们在这个情况下做计数即可。

(此时,\(R=K\) )。最后结果的左部一定是所有数中最大的 \(L\) 个且按照升序排列,所以如果 \(B\) 序列最左边的数不是所有数中最大的或者不是升序的,那么方案数为 \(0\)(所有数并不包含在之前的操作中扔掉的数)

\(K\) 轮操作之后的右部是 \(\{x_1,x_2,...,x_{R}\}\) ,最初的序列的左部是 \(\{a_1,a_2,...,a_{L}\}\) ,右部是 \(\{b_1,b_2,...,b_{R}\}\)

如果右部中存在 \(x_{i-1}>x_{i}\) 的情况,那么最初的序列的右部第 \(i\) 项(\(b_i\))一定是 \(x_i\) ,因为 \(x_{i-1}\) 是第 \(i-1\) 次操作被左部扔出来的数,而 \(x_i\) 是第 \(i\) 次操作扔出来的数。\(x_i<x_{i-1}\) 说明 \(x_i\) 这个数一定是第 \(i\) 次操作进的左部,刚进去就被扔出来了。

现在忽略掉上面这种 \(x,b\) ,剩下的 \(x\) 一定是升序的。那么对于每一个剩下的 \(x\) ,都有一下要求:

  • \(a_1,a_2,...,a_{L},b_1\) 中的一个等于 \(x_1\)
  • \(a_1,a_2,...,a_{L},b_1,b_2\) 中的一个等于 \(x_2\)
  • \(a_1,a_2,...,a_{L},b_1,b_2,b_3\) 中的一个等于 \(x_3\)
  • ......

可以发现对于每一个 \(x\) 都有 \((L+1)\) 中选择方式,所以一共有 \((L+1)^{t}\) 中初始序列(\(t\) 是剩下的 \(x\) 个数)。

又因为原来的左部是无序的,所以答案还应该再乘上 \(L!\)

复杂度:\(\mathcal O(N)\)

代码:Link

posted @ 2022-10-04 14:38  Vitheon  阅读(125)  评论(0编辑  收藏  举报