[R28C]最大操作数


1n2×1051 \le n \le 2 \times 10^51Ai,Bi1091 \le A_i, B_i \le 10^90Y1090 \le Y \le 10^9

思路

递推式为 Xi=Xi1/AiBiX_i = \lfloor X_{i-1}/A_i \rfloor - B_i,已知末项 Xn=YX_n = Y,要求使整条链合法的最大 X0X_0

把递推式反过来:Xi1/Ai=Xi+Bi\lfloor X_{i-1}/A_i \rfloor = X_i + B_i。设 q=Xi+Biq = X_i + B_i,则满足 t/Ai=q\lfloor t / A_i \rfloor = q 的整数 tt 恰好构成区间

[Aiq, Ai(q+1)1].[A_i \cdot q,\ A_i \cdot (q+1) - 1].

要让最终的 X0X_0 尽量大,每一步倒推时都应该取这个区间的右端点,于是得到一个确定的反向递推:

Xi1=Ai(Xi+Bi+1)1.X_{i-1} = A_i \cdot (X_i + B_i + 1) - 1.

这是一个关于 XiX_i仿射函数(形如 f(x)=mx+cf(x) = m x + c)。从 Xn=YX_n = Y 倒推到 X0X_0,相当于把若干个仿射函数复合起来,结果仍是关于 YY 的仿射函数:

X0max=aY+b.X_0^{\max} = a \cdot Y + b.

只要维护这组系数 (a,b)(a, b),并对 p=998244353p = 998244353 取模即可,无需关心 X0X_0 真实有多大。复合规则:若当前 Xi=aY+bX_i = aY + b,则

Xi1=Ai(aY+b+Bi+1)1=(Aia)Y+(Ai(b+Bi+1)1),X_{i-1} = A_i(aY + b + B_i + 1) - 1 = (A_i \cdot a) Y + (A_i(b + B_i + 1) - 1),

aAia,bAi(b+Bi+1)1.a \leftarrow A_i \cdot a,\qquad b \leftarrow A_i \cdot (b + B_i + 1) - 1.

初值 a=1, b=0a = 1,\ b = 0(代表 Xn=YX_n = Y),从 i=ni = n 倒推到 i=1i = 1,最后答案为 (aY+b)modp(a \cdot Y + b) \bmod p

注:每步都取右端点能保证全局最优,因为反向递推每一步都是 Xi1X_{i-1} 关于 XiX_i 的严格递增函数,前一步取更大值传递下去一定让最终结果更大。

复杂度

  • 时间:O(n)O(n),一次倒推遍历。
  • 空间:O(n)O(n),存储数组 AABB

仓颉实现

import std.convert.*
import std.env.*

main(): Int64 {
    let reader = getStdIn()
    let n = Int64.parse(reader.readln().getOrThrow())
    let aArr = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
    let bArr = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
    let y = Int64.parse(reader.readln().getOrThrow())
    let mod = 998244353
    // 倒推:X_{i-1}_max = A_i*(X_i + B_i + 1) - 1,是关于 X_i 的仿射函数。
    // 维护最终 X_0_max = a*Y + b (mod p),初始 a=1, b=0。
    var a = Int64(1)
    var b = Int64(0)
    var i = n - 1
    while (i >= 0) {
        let ai = aArr[i] % mod
        let bi = bArr[i]
        // new_a = A_i * a ; new_b = A_i * (b + B_i + 1) - 1
        a = (ai * a) % mod
        b = (ai * ((b + bi + 1) % mod) % mod + mod - 1) % mod
        i = i - 1
    }
    let ans = ((a * (y % mod)) % mod + b) % mod
    println(ans)
    return 0
}