1 条题解

  • 0
    @ 2025-11-6 11:32:39

    1. 题意理解

    我们有一个数字串 SS,长度 n500n \le 500

    定义 f(x)f(x) 表示把整数 xx 拆分成若干个 1m1 \sim m 的数的和的方案数(顺序不同视为不同方案)。
    这其实就是:用 1,2,,m1, 2, \dots, m 来组成 xx有序拆分的个数。

    例如 m=2m=2 时,f(4)=5f(4)=5,因为:

    4=1+1+1+1=2+1+1=1+2+1=1+1+2=2+24 = 1+1+1+1 = 2+1+1 = 1+2+1 = 1+1+2 = 2+2

    g(S)g(S) 的定义
    把数字串 SS 任意切成若干段(每段是一个数,允许前导零),把每段对应的整数加起来得到 TT,然后计算 f(T)f(T),并对所有切分方案求和。

    例如 S=S = "123":

    • 切分 "1231|2|3" → 1+2+3=61+2+3=6,求 f(6)f(6)
    • 切分 "1231|23" → 1+23=241+23=24,求 f(24)f(24)
    • 切分 "12312|3" → 12+3=1512+3=15,求 f(15)f(15)
    • 切分 "123123" → 123123,求 f(123)f(123)

    g(123)=f(6)+f(24)+f(15)+f(123)g(123) = f(6) + f(24) + f(15) + f(123)


    2. 先分析 f(x)f(x) 的计算

    f(x)f(x)有序拆分1m1 \dots m 的方案数。
    这是一个经典的递推问题

    f(0)=1(空拆分)f(0) = 1 \quad (\text{空拆分}) $$f(k) = f(k-1) + f(k-2) + \dots + f(k-m), \quad k \ge 1 $$

    其中 f(k)=0f(k) = 0k<0k < 0

    解释:最后一步可以放 1,2,,m1, 2, \dots, m,所以从 f(k1)f(k-1) 等转移过来。


    因为 m5m \le 5,这个递推是线性的,可以用矩阵快速幂来求 f(x)f(x)998244353998244353 取模的值。
    xx 可能很大(字符串长度 500500,数字总和最大是 9×500=45009 \times 500 = 4500?不对,切分后加起来可能很大,因为一段可能是一个几百位数)。
    例如 SS 全是 99,长度 500500,那么 TT 最大可能是这个 500500 位数本身,即 1050010^{500} 量级,不可能直接算 f(T)f(T)


    3. 关键观察

    f(x)f(x) 的递推是线性递推,模 998244353998244353 下,f(x)f(x)xx 很大时可以用矩阵快速幂计算,但 xx 可能极大(几百位十进制数),直接对 xx 做快速幂不行。
    但是,线性递推在模 pp 下具有周期性,并且 f(x)f(x) 可以表示成矩阵 MMxx 次幂的形式。

    设:

    $$F_k = \begin{bmatrix} f(k) & f(k-1) & \dots & f(k-m+1) \end{bmatrix}^T $$

    那么:

    Fk=MFk1F_k = M \cdot F_{k-1}

    其中 MMm×mm \times m 矩阵:

    $$M = \begin{bmatrix} 1 & 1 & 0 & 0 & \dots & 0 \\ 1 & 0 & 1 & 0 & \dots & 0 \\ 1 & 0 & 0 & 1 & \dots & 0 \\ \vdots & & & & \ddots & \vdots \\ 1 & 0 & 0 & \dots & 0 & 1 \\ 1 & 0 & 0 & \dots & 0 & 0 \end{bmatrix} $$

    (第一列全是 11,次对角线下方的 11 的位置对应递推)

    更准确地说,对于 mm

    $$M_{1,j} = 1 \ (1 \le j \le m),\quad M_{i,i-1} = 1 \ (2 \le i \le m),\ 其余为 0 $$

    检查一下:
    Fk[1]=f(k)=f(k1)+f(k2)++f(km)F_k[1] = f(k) = f(k-1) + f(k-2) + \dots + f(k-m) 对应第一行全 11
    Fk[i]=f(ki+1)=Fk1[i1]F_k[i] = f(k-i+1) = F_{k-1}[i-1] 对应 Mi,i1=1M_{i,i-1}=1


    于是:

    Fx=MxF0F_x = M^x \cdot F_0

    其中 F0=[1,0,0,,0]TF_0 = [1, 0, 0, \dots, 0]^T

    所以 f(x)=(Mx)1,1f(x) = (M^x)_{1,1}(因为 Fx[1]=(MxF0)[1]=(Mx)1,1F_x[1] = (M^x \cdot F_0)[1] = (M^x)_{1,1})。


    4. 问题转化为:对所有切分方案,求 MsumM^{\text{sum}}(1,1)(1,1) 元素之和

    设一种切分方式得到的各段数值为 a1,a2,,ata_1, a_2, \dots, a_t,则 T=a1+a2++atT = a_1 + a_2 + \dots + a_t

    我们要的是:

    $$\sum_{\text{partition}} (M^{a_1 + a_2 + \dots + a_t})_{1,1} $$

    注意矩阵幂的性质:
    Ma+b=MaMbM^{a+b} = M^a \cdot M^b

    所以:

    $$M^{a_1 + \dots + a_t} = M^{a_1} \cdot M^{a_2} \cdots M^{a_t} $$

    我们要求的是这个乘积的 (1,1)(1,1) 元素的和。


    5. 动态规划

    dp[i]dp[i] 表示考虑前 ii 个字符的所有切分方式下,矩阵乘积的和(一个 m×mm \times m 矩阵)。

    初始:dp[0]=Idp[0] = I(单位矩阵)。

    转移:
    $dp[i] = \sum_{j=0}^{i-1} dp[j] \cdot M^{\text{num}[j+1:i]}$

    其中 num[j+1:i]\text{num}[j+1:i] 是子串 S[j+1..i]S[j+1..i] 对应的整数。


    最终答案 = dp[n]dp[n](1,1)(1,1) 元素。

    因为 n500n \le 500,直接做是 O(n3m3)O(n^3 m^3) 会太大(矩阵乘法 m3m^3mm 很小,主要是 n3n^3 大)。
    需要优化:num[j+1:i]\text{num}[j+1:i] 可能很大,但 MnumM^{\text{num}} 是在模 998244353998244353 下,且指数可对矩阵的阶取模?
    矩阵在模 pp 下的阶至多是 pm1p^m - 1 量级,但 pp 很大,不能直接降指数。


    6. 大指数矩阵快速幂

    对于 MnumM^{\text{num}},其中 num\text{num} 是几百位十进制数,我们可以用十进制矩阵快速幂
    预处理 M1,M10,M100,M^1, M^{10}, M^{100}, \dots,然后按数字位乘起来。

    这样计算 MnumM^{\text{num}}O(lenm3)O(\text{len} \cdot m^3),len 是 num 的位数。


    7. 最终算法

    1. 预处理 MM10k10^k 次幂,k=0..nk=0..n
    2. DP:
      dp[0]=Idp[0] = I
      对于 i=1..ni=1..n
      dp[i]=0dp[i] = 0(矩阵)
      对于 j=i1..0j=i-1..0
      numnum = 子串 S[j+1..i]S[j+1..i] 对应的整数(可能很大,但我们用十进制矩阵快速幂算 MnumM^{num}
      dp[i] +=dp[j]Mnumdp[i] \ += dp[j] \cdot M^{num}
    3. 输出 dp[n][1,1]dp[n][1,1]

    复杂度:O(n3m3log?)O(n^3 m^3 \log ?) 还是大,但 n=500n=500n3=1.25×108n^3=1.25\times 10^8,不可行。
    需要优化:注意到从 jjiinumnum 是 $num_{j+1,i} = num_{j+1,i-1} \times 10 + (S[i] - '0')$。
    我们可以从小到大枚举 ii,同时维护 Mnumj,iM^{num_{j,i}},这样不用每次都做十进制快速幂。


    具体:
    对每个 jj,维护 Pj=Mnum[j+1..i]P_j = M^{\text{num}[j+1..i]},当 ii 增加时,Pj=Pj10MS[i]0P_j = P_j^{10} \cdot M^{S[i]-'0'}
    Pj10P_j^{10} 还是需要做矩阵快速幂(1010 次幂很快,因为 mm 小)。

    这样每步是 O(nm3log10)O(n m^3 \log 10),总 O(n2m3log10)O(n^2 m^3 \log 10),可过。


    8. 总结

    算法步骤

    • 定义 m×mm \times m 转移矩阵 MM
    • dp[i]dp[i]m×mm \times m 矩阵,表示前 ii 个字符的所有切分对应的矩阵乘积之和。
    • 初始 dp[0]=Idp[0] = I
    • i=1..ni=1..n
      • 初始化 dp[i]dp[i] 为零矩阵。
      • j=0..i1j=0..i-1
        • 计算 Mnum[j+1..i]M^{\text{num}[j+1..i]},利用上一步的 Mnum[j+1..i1]M^{\text{num}[j+1..i-1]}( )10Md(\ )^{10} \cdot M^{d}
      • 更新 dp[i]+=dp[j]matdp[i] += dp[j] \cdot \text{mat}
    • 输出 dp[n][1,1]dp[n][1,1]
    • 1

    信息

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