1 条题解

  • 0
    @ 2026-4-21 22:45:32

    题目重述 给定一个字符串 tt,判断是否存在一个字符串 ss 和一个正整数 LL1L<s1 \le L < |s|),使得 tt 由两个 ss 重叠 LL 个字符拼接而成,即 t=s+s[L:] t=s+s[L:] 其中 s[L:]s[L:] 表示 ss 去掉前 LL 个字符的后缀。 例如,s="abrakadabra"s = \text{"abrakadabra"}L=4L=4 时,t="abrakadabrakadabra"t = \text{"abrakadabrakadabra"}

    要求:若存在,输出任意一个可能的 ss;否则输出 "NO"。 数据范围:t4×105|t| \le 4\times 10^5

    数学建模 设 s=m|s| = mt=n|t| = n。由拼接方式知: n=m+(mL)=2mL n=m+(m−L)=2m−L 因此重叠长度 L=2mnL = 2m - n

    题目要求 1L<m1 \le L < m,即 12mn<m 1≤2m−n<m 解不等式:

    左边 2mn1;;mn+122m - n \ge 1 ;\Rightarrow; m \ge \frac{n+1}{2}

    右边 2mn<m;;m<n2m - n < m ;\Rightarrow; m < n

    由于 mm 是整数,所以 mm 的取值范围为:

    n/2+1mn1\lfloor n/2 \rfloor + 1 \leq m \leq n-1

    换言之,我们只需枚举 mm 在这个区间内的每个整数,令 L=2mnL = 2m - n,然后验证以下两个条件:

    后缀条件:t[m..n1]t[m..n-1] 等于 t[L..m1]t[L..m-1] (因为 tt 的后半部分应该是 s[L:]s[L:],而 s[L:]s[L:] 恰好是 tt[L,m1][L, m-1] 段)

    前缀条件:t[0..L1]t[0..L-1] 等于 t[mL..m1]t[m-L..m-1] (因为 ss 的前 LL 个字符与后 LL 个字符相同——它们就是重叠部分)

    若存在某个 mm 同时满足这两个条件,则 s=t[0..m1]s = t[0..m-1] 即为答案。

    关键观察 如果直接对每个 mm 比较子串,最坏情况需要 O(n2)O(n^2),不可接受。

    我们需要一种能在 O(1)O(1) 时间内判断任意两个子串是否相等的方法。

    常用的工具有:字符串哈希、Z 函数、前缀函数(KMP)。这里选用简单高效的哈希法。

    算法设计(哈希法)

    1. 预处理哈希 选择一个大质数模数 PP(例如 109+710^9+7)或使用自然溢出(2642^{64})。定义基数 BB(例如 9113823391138233131131)。 对于字符串 tt(下标从 00 开始),计算前缀哈希数组 hh 和幂数组 pp

    h[0]=0h[0]=0

    h[i+1]=(h[i]B+(t[i]a+1))modPh[i+1]=(h[i]⋅B+(t[i]−'a'+1))modP

    p[0]=1p[0]=1

    p[i+1]=p[i]BmodPp[i+1]=p[i]⋅BmodP

    则子串 t[l..r]t[l..r]0lr<n0 \le l \le r < n)的哈希值为:

    hash(l,r)=(h[r+1]h[l]p[rl+1])modPhash(l,r)=(h[r+1]−h[l]⋅p[r−l+1])modP 若使用自然溢出(unsigned long long),则自动模 2642^{64},无需取模操作。

    1. 枚举 mmm=n/2+1m = \lfloor n/2 \rfloor + 1m=n1m = n-1,依次检查:

    计算 L=2mnL = 2m - n(此时 1L<m1 \le L < m 自动成立)

    检查 $\text{hash}(m, n-1) \stackrel{?}{=} \text{hash}(L, m-1)$

    检查 $\text{hash}(0, L-1) \stackrel{?}{=} \text{hash}(m-L, m-1)$

    如果两个条件都满足,则输出 s=t[0..m1]s = t[0..m-1],结束程序。

    若循环结束未找到,输出 "NO"。

    边界情况处理 当 n2n \le 2 时,mm 的取值范围为空(因为 n/2+1n\lfloor n/2 \rfloor + 1 \ge n),直接输出 "NO"。例如 n=1n=1n=2n=2 不可能构成错误。

    注意题目明确:完全重叠(L=0L=0)或简单拼接(L=mL=m)不算错误,我们的枚举范围自然排除了这些情况。

    字符串中可能包含相同字符,哈希能够正确处理。

    复杂度分析 预处理哈希:O(n)O(n)

    枚举 mm:最多 O(n)O(n)

    每次判断:O(1)O(1)

    总时间复杂度:O(n)O(n)

    空间复杂度:O(n)O(n)(存储哈希数组和幂数组)

    对于 n4×105n \le 4\times10^5,完全可行。 必要性: 若存在 ssLL 使得 t=s+s[L:]t = s + s[L:],设 m=sm = |s|,则 n=2mLn = 2m - L,故 L=2mnL = 2m - n。由 1L<m1 \le L < m 可得 mmn/2+1\lfloor n/2 \rfloor + 1n1n-1 之间。

    因为 t[m..n1]=s[L:]=t[L..m1]t[m..n-1] = s[L:] = t[L..m-1],所以条件1成立。

    又因为 ss 的前 LL 个字符与后 LL 个字符相同(即重叠部分),所以 t[0..L1]=s[0..L1]=s[mL..m1]=t[mL..m1]t[0..L-1] = s[0..L-1] = s[m-L..m-1] = t[m-L..m-1],条件2成立。 因此算法一定会找到这样的 mm

    充分性: 若对于某个 mm 满足上述两个条件,令 s=t[0..m1]s = t[0..m-1]L=2mnL = 2m - n。条件1说明 t[m..n1]=s[L:]t[m..n-1] = s[L:],条件2说明 s[0..L1]=s[mL..m1]s[0..L-1] = s[m-L..m-1]。那么 t=s+s[L:]t = s + s[L:],且 L=2mnL = 2m-n 满足 1L<m1 \le L < m(由 mm 的范围保证),因此 ss 是一个合法解。

    综上,算法正确。

    • 1

    信息

    ID
    6615
    时间
    1000ms
    内存
    256MiB
    难度
    3
    标签
    递交数
    1
    已通过
    1
    上传者