问题引入:求 $\sum_{i=1}^n\lfloor\frac{a\times i+b}{c}\rfloor$。期望复杂度 $O(T\log n)$。

考虑引入函数 $y=\frac{ax+b}{c}$,$x\in(0,n]$,则从 $x=0$ 出发,维护两个变量 $A,B$ 初始为 $0$,执行以下操作:

  • 遇到 $y=h$ 就让 $A\gets A+1$;
  • 遇到 $x=k$ 就让 $B\gets B+A$。

优先执行第一条,最终的 $B$ 就是答案。不难发现 $b$ 可以直接对 $c$ 取模,因为在这个转化后的问题中只关心越过两类网格线的次数。

不妨写下一个字符串 $S$,过程中每遇到一次 $y=h$ 就在末尾写下一个 U,每遇到一次 $x=k$ 就在末尾写下一个 R,最终的答案只和这个字符串有关。

考虑把这两种规则看作某种线性变换(容易构造矩阵表示/合并),分别为 $f_U,f_R$,即向上越过网格线和向右越过网格线的影响。即答案为初始两个变量,依次经过 $S$ 中的每一个变换后最终得到的值。由于结合律可以优先合并变换。

更形式化一点,记 $g(a,b,c,n,f_U,f_R)$ 为这个过程后合并得到的变换,进行一些讨论:

  • 若 $a\ge c$,则每个 R 前至少有 $\lfloor\frac{a}{c}\rfloor$ 个 U,把它们合并起来,则答案为 $g(a\bmod c,b,c,n,f_U,f_U^{\lfloor\frac{a}{c}\rfloor}\cdot f_R)$;
  • 若 $a<c$,尝试类似辗转相除法地交换 $a,c$,那么要交换 U,R 的地位:

    • 第 $p$ 个 R 前共有 $\lfloor\frac{ap+b}{c}\rfloor$ 个 U,假设第 $q$ 个 U 在第 $p$ 个 R 之后:

      • $q>\lfloor\frac{ap+b}{c}\rfloor\ge \frac{ap+b}{c}$,移项得 $p<\frac{cq-b}{a}$,由于 $a,b,c,q,p\in\mathbb{Z}^+$,有 $p\leq \lfloor\frac{cq-b-1}{a}\rfloor$。
    • 那么第 $q$ 个 U 前共有 $\lfloor\frac{cq-b-1}{a}\rfloor$ 个 R,注意其包括与其同时加入的 R
    • 转化为了另一个形式类似的问题,即 $y=\frac{cx-b-1}{a}$,$y\in(0,n]$,求总变换。不妨设 $m=\lfloor\frac{an+b}{c}\rfloor$,则 $x\in(0,m]$。
    • 现在面临和原问题不同的部分是:

      1. $b'=-b-1$,不满足 $b'\in[0,c')$;
      2. 在 $x>m$ 时虽然没有新的 R,但可能存在部分 U 未被写入。
    • 对于第一个问题,由于 $c-b-1\ge 0$,可以通过特殊计算 $x\leq 1$ 的部分再递归剩下部分来解决;对于第二个问题,可以特殊计算 $x>m$ 部分 U 的个数来解决。
    • 特殊地,递归的边界是 $m=0$ 时返回 $f_R^n$。否则递归计算 $f_R^{\lfloor\frac{c-b-1}{a}\rfloor}\cdot f_U\cdot g(c,c-b-1,a,m-1,f_R,f_U)\cdot f_R^{n-\lfloor\frac{cm-b-1}{a}\rfloor}$。

设计算一次 $f\cdot f\to f$ 的复杂度是 $O(t)$,则计算 $f^k$ 的复杂度是 $O(t\log k)$,每轮递归的 $k=O(\frac{a}{c})$,则复杂度为 $O(t\log a-t\log c)$,总复杂度 $T(a,c)=T(c,a\bmod c)+O(t\log a-t\log c)=O(t\log \max\{a,c\})$。

对于这个例题(【模板】类欧几里得算法 的第一部分),需要维护三元组 $(cntU,cntR,ans)$ 表示经过的 U,R 的个数以及当前答案,初始 $f_U=(1,0,0),f_R=(0,1,0)$。那么合并三元组 $(a,b,c)\cdot (d,e,f)=(a+d,b+e,c+f+ae)$,注意在题目限制下需要额外加上 $i=0$ 的答案。本质是后半部分贡献 $y\to (y+a)$。

第二部分需要求 $\sum_{i=0}^n{\lfloor\frac{ai+b}{c}\rfloor}^2$,合并依赖第一部分的和,即后半部分的贡献 $y^2\to (y+a)^2$。

第三部分需要求 $\sum_{i=0}^ni\lfloor\frac{ai+b}{c}\rfloor$,合并依赖第一部分的答案以及 $x$ 的和,即后半部分的贡献 $xy\to (x+a)(y+b)$。

实际代码实现中只需要修改合并部分,递归部分都是完全一致的。

node g(int a,int b,int c,int n,node U,node R){
    if(!n)return node();if(b>=c)b%=c;
    if(a>=c)return g(a%c,b,c,n,U,U*(a/c)+R);
    int m=(a*n+b)/c;if(!m)return R*n;
    return R*((c-b-1)/a)+U+g(c,c-b-1,a,m-1,R,U)+R*(n-(c*m-b-1)/a);
}

在本题中三个部分一共需要维护 6 个变量分别表示 $y,x,\sum x,\sum y,\sum y^2,\sum xy$,注意 $f_U,f_R$ 的初始值有不同,因为 RU 多一个结算,所以初始 $f_U$ 中仅有 $y=1$,$f_R$ 中有 $x=\sum x=1$。

最后修改:2022 年 08 月 26 日
如果觉得我的文章对你有用,请随意赞赏