题解:P3318 [SDOI2015] 双旋转字符串

· · 题解

洛谷 P3318双旋转字符串

标题有些吓人啊!

但其实只要读懂题意还是挺简单的

题目解析(原题点这里)

我们如果想 AC 就要读懂题目。 我们要理解什么是“双螺旋性”

举个栗子:qwer 的双旋转字符串有 qwer,werq,erqw,rqwe。

简单说就是一个长度为偶数的字符串 W 可以分为两部分 UV ,如果 VU 旋转得到的,那么 W 就是双旋转性的

关于字符串的题目就是拼理解力,题目有点难理解

正片开始

给定两个字符串集合 ST,S 中的字符串长度为 N,T 中的字符串长度为 M ,且 N + M 是偶数。需要找出 ST 中字符串对 (Si, Tj),使得 Si + Tj 满足双旋转性。
首先,N + M 是偶数,所以 Si + Tj 的总长度是偶数,可以分为两部分,每部分长度为 \displaystyle \frac{N+M}{2}

正常的话其实可以暴力枚举
但是时间复杂度 O(TotalS TotalT (N + M)),包超时的呀。

这种题目就只能用哈希解决了,我只会哈希解,太弱了,如果有更好的题解请大佬指教。

具体步骤

1.读取输入参数: TotalS, TotalT, N, M

2.读取 TotalS 个字符串,存储在数组S中。

3.读取 TotalT 个字符串,存储在数组T中。

4.计算 L = \displaystyle \frac{N+M}{2}

5.初始化一个字典 map,键是字符串的最小表示,值是拥有该最小表示的 Si 的数量。

6.对于每个 Si in S

7.对于每个 Tj in T

8.构造 W = Si + Tj

9.提取 U = W[0...L-1]

10.计算 U 的最小表示 minU

11.将 minUmap 中对应的计数加 1。

12.初始化结果计数器 count = 0

13.对于每个 Tj in T

14.构造 V = W[L...2L-1]。

15.计算 V 的最小表示 minV

16.如果 minV 在 map 中存在,将 count 加上 map[minV]

17.输出 count

但是还是会 TLE。

优化

注意到 UV 分别来自 SiTj,且 W = Si + Tj

所以, UW 的前 L 个字符, V 是后 L 个字符。

由于 W = Si + Tj,所以 U 是由 Si 的前 L - M 个字符和 Tj 的前 M - (L - N) 个字符组成。

需要根据 N和M的大小关系来确定U和V如何从Si和Tj中提取。 有以下情况: 情况一:N \le L

具体来说, $$U = Si[0...N-1] + Tj[0...L - N -1]。$$ 情况二: $N > L$。 $U$ 完全在 $Si$ 中。 $$ U = Si[0...L-1] $$ 情况三: $M \ge L$。 $V$ 完全或部分在 $Tj$ 中。 $$ V = Tj[0...M-1] $$ 情况四: $M > L$。 $$V = Tj[0...L-1]$$ 但是,实际上,由于 $N + M$ 是偶数,且 $\displaystyle \frac{N+M}{2}$,所以需要根据 $N$ 和 $M$ 与 $L$ 的关系来确定 $U$ 和 $V$ 如何从 $Si$ 和 $Tj$ 中提取。 这可能比较复杂,需要更仔细地处理。 也许,更好的方法是,对于每个 $Si$ 和 $Tj$,直接构造 $W = Si + Tj$,然后提取 $U$ 和 $V$,计算它们的最小表示,然后检查是否相同。 虽然时间复杂度较高,但由于 $TotalS$ 和 $TotalT$ 都是 $100$, $L$ 是 $100$,总时间复杂度是 $1e7$,可能在时间限制内。 我们可以尝试减少计算量。 例如,预先计算所有 $Si$ 的 $U$ 的最小表示,存储在 map 中。 然后,对于每个 $Tj$,计算 $V$ 的最小表示,然后在 map 中查找匹配的计数。 但是,由于 $U$ 和 $V$ 的长度都是 $L$,且 $L$ 可以是 $100$,map 的键是字符串,可能空间和时间开销都比较大。 可能需要使用更高效的字符串表示方法,比如字符串哈希。 可以使用滚动哈希来计算 $U$ 和 $V$ 的哈希值,然后比较它们的最小表示的哈希是否相等。 这样可以加速匹配过程。 ### 加速 定义一个函数,计算字符串的最小表示的哈希。 对于每个 $Si$ 和 $Tj$,计算 $U$ 和 $V$ 的最小表示的哈希。 如果 $U$ 和 $V$ 的最小表示的哈希相等, $则计数加1$。 这样,时间复杂度主要是计算最小表示的哈希,可以优化到 $O(L)$。 总时间复杂度是 $O(TotalS TotalT L)$,可能在时间限制内。 可能需要进一步优化。 另一个思路是,对于 $S$ 中的每个 $Si$,计算 $U$ 的最小表示的哈希,并存储在 map 中。 然后,对于每个 $Tj$,计算 $V$ 的最小表示的哈希,然后在 map 中查找匹配的计数,累加到结果中。 这样,时间复杂度是 $O(TotalS L + TotalT L)$,因为 map 的操作是 $O(1)$。 这是更优的解决方案。 **记住一定要用快速幂!!!**。 (~~本人就是在这里被坑的~~) 读取 $TotalS, TotalT, N, M$。 读取 $S$ 中的所有字符串,存储在数组 $S$ 中。 读取 $T$ 中的所有字符串,存储在数组 $T$ 中。 计算 $ L = \displaystyle\frac{N+M}{2}$。 初始化一个字典 map,键是最小表示的哈希,值是拥有该哈希的 $Si$ 的数量。 对于每个 $Si in S:

构造 W = Si + Tj (暂时不指定 Tj)

但由于需要提取 U = W[0...L-1]

但是, Tj 还没有确定,所以需要对于每个 Tj ,构造 W,提取 U

然后,对于每对 (Si, Tj),执行以下步骤:

构造 W = Si + Tj

提取 U = W[0...L-1]

提取 V = W[L...2L-1]

计算 minU = min_rotation(U) 的哈希。

计算 minV = min_rotation(V) 的哈希。

如果 minU == minV,则计数加 1

其中,min_rotation 函数返回字符串的最小旋转表示。

综上所述,最直接的方法是对于每对 (Si, Tj),计算 UV 的最小表示的哈希,并比较是否相等。

尽管时间复杂度较高,但数据规模较小,应该是可以接受的。

现在来实现这个算法。

首先,实现一个函数来计算字符串的最小表示的哈希。

为了高效,可以使用滚动哈希。

定义一个大质数 P 和基数 B,然后计算字符串的哈希值。

为了找到最小表示,需要找到所有循环移位中的最小哈希值。

代码

代码还是比较简单的。

点这里看代码哟。
综合时间复杂度为 O(n^2+2nlogn)

欢迎指出错误和不足