1 条题解

  • 0
    @ 2025-10-22 17:23:17

    题意理解

    我们有一个无限长的 Thue-Morse 序列,定义:

    • T0=0T_0 = 0
    • T2n=TnT_{2n} = T_n
    • T2n+1=1TnT_{2n+1} = 1 - T_n

    给定一个 01 字符串 SS 和整数 kk,问有多少个 Thue-Morse 序列的连续子序列 TT 满足:

    • SSTT 的前缀
    • TT 的长度 = S+k|S| + k

    核心难点

    1. Thue-Morse 序列的结构特殊:具有自相似性
    2. kk 极大:最大 101810^{18},需要对数算法
    3. 需要高效判断和计数:哪些扩展是合法的连续子序列

    关键观察:Thue-Morse 序列的性质

    自相似性

    Thue-Morse 序列可以递归生成:

    • 00 开始
    • 每次替换:0010 \to 01, 1101 \to 10

    也就是说:

    • 位置 2n2nnn 相同
    • 位置 2n+12n+1nn 相反

    问题转化

    我们有一个前缀 SS,要在后面添加 kk 位,使得整个串是 Thue-Morse 序列的连续子序列。

    关键思路:从某个起始位置 pp 开始,取长度为 S+k|S|+k 的子串,这个子串的前 S|S| 位等于 SS


    递归求解框架

    基础想法

    f(S,k)f(S, k) 表示以 SS 为前缀,后面添加 kk 位的方案数。

    由于 Thue-Morse 序列的递归结构,我们可以将问题分解:

    1. 如果 SS 能匹配序列中从偶数位置开始的一段

      • 那么 SS 的每个字符 S[i]S[i] 必须等于 T2n+i=Tn+i/2T_{2n+i} = T_{n + i/2}(当 ii 为偶数时)
      • 这实际上要求 SS 的偶数位和奇数位分别满足某种关系
    2. 更直接的方法:考虑 SS 在序列中的出现位置


    关键性质:递推关系

    通过分析 Thue-Morse 序列的结构,可以发现:

    对于字符串 SS 和整数 kkf(S,k)f(S, k) 满足:

    • 基本情况

      • 如果 SS 不是 Thue-Morse 序列的子序列:f(S,k)=0f(S, k) = 0
      • 如果 k=0k = 0:检查 SS 本身是否是连续子序列
    • 递归情况

      • 如果 SS00 开头,考虑两种可能:
        • 从某个偶数位置开始:f(S,k)=f(S,k/2)f(S, k) = f(S', \lfloor k/2 \rfloor),其中 SS'SS 的某种变换
        • 从某个奇数位置开始:类似处理
      • 实际上更精确的递推是:

    核心递推式

    SS 是当前模式,kk 是要添加的长度。

    我们可以将 SS 按位分解,利用 Thue-Morse 序列的生成规则:

    规则TnT_nTn/2T_{\lfloor n/2 \rfloor} 有关系:

    • 如果 nn 是偶数:Tn=Tn/2T_n = T_{n/2}
    • 如果 nn 是奇数:Tn=1Tn/2T_n = 1 - T_{\lfloor n/2 \rfloor}

    因此,如果我们知道 SS 匹配从位置 pp 开始的子串,那么:

    • S[0]=TpS[0] = T_p
    • S[1]S[1] 必须等于 Tp+1T_{p+1},而 Tp+1T_{p+1}T(p+1)/2T_{\lfloor (p+1)/2 \rfloor} 决定

    实际算法:记忆化搜索

    定义 dp(S,k)dp(S, k)

    1. 边界情况

      • 如果 S=1|S| = 1k=0k = 0:返回 1(只有 SS 本身)
      • 如果 S=1|S| = 1k>0k > 0:考虑两种扩展方式
    2. 递归分解

      • SS 分成两部分:S=A+BS = A + B,其中 A=1|A| = 1A=2|A| = 2
      • 检查 AA 是否是合法的 Thue-Morse 模式
      • 如果能匹配,问题转化为 dp(B,k/2)dp(B, \lfloor k/2 \rfloor) 等子问题

    具体递推关系

    经过推导,可以得到:

    对于 SSkk,设:

    • S0S_0 = SS 去掉第一个字符后,根据 S[0]S[0] 的值可能需要对剩余字符取反
    • S1S_1 = SS 去掉前两个字符后,根据前两个字符的值进行变换

    那么:

    $$f(S, k) = f(S_0, \lfloor k/2 \rfloor) + f(S_1, \lfloor (k-1)/2 \rfloor) $$

    其中 S0S_0S1S_1 是根据 Thue-Morse 生成规则得到的子问题。


    处理大 kk

    由于 kk 可达 101810^{18},递归深度只有 O(logk)O(\log k),但 SS 的长度不超过 100100

    我们可以用记忆化搜索

    • 状态:(S,k)(S, k)
    • kk 很大,实际上我们只需要记录 SS 和递归深度

    因为每次 kk 会除以 2,所以最多 O(logk)O(\log k) 层递归。


    算法框架(伪代码)

    map<pair<string, ll>, int> memo;
    
    int solve(string S, ll k) {
        if (memo.count({S, k})) return memo[{S, k}];
        
        int n = S.length();
        
        // 边界情况
        if (n == 0) return 1;  // 空串可以任意扩展
        if (k == 0) return check(S) ? 1 : 0;  // 检查S本身是否合法
        
        // 递归分解
        int res = 0;
        
        // 情况1:匹配第一个字符
        string S0 = transform(S, 1);  // 根据Thue-Morse规则变换剩余字符串
        if (S0 != "INVALID") {
            res += solve(S0, k / 2);
        }
        
        // 情况2:匹配前两个字符  
        if (n >= 2) {
            string S1 = transform(S, 2);  // 根据前两个字符变换
            if (S1 != "INVALID") {
                res += solve(S1, (k - 1) / 2);
            }
        }
        
        return memo[{S, k}] = res % MOD;
    }
    

    复杂度分析

    • 状态数:O(Slogk)O(|S| \cdot \log k)
    • 每个状态处理时间:O(S)O(|S|)
    • 总复杂度:O(TS2logk)O(T \cdot |S|^2 \cdot \log k),可以接受

    总结

    这道题的核心在于:

    1. 理解 Thue-Morse 序列的递归结构
    2. 将匹配问题分解为子问题:每次处理 1-2 个字符
    3. 利用记忆化搜索处理大 kk:递归深度只有对数级别
    4. 设计正确的状态转移:根据序列生成规则变换剩余字符串

    通过这种分解,我们就能在 kk 极大时高效求解。

    • 1

    信息

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