P1036 · OFFICIAL SOLUTION

P1036 星脉聚流光 官方题解

Gioush OJ · P1036 星脉聚流光

星脉聚流光

【题意简述】

对于每个满足 1xn1\leq x\leq n1ym1\leq y\leq m 的整点 (x,y)(x,y),连接 (0,0)(0,0)(x,y)(x,y)。若线段内部经过 kk 个其他整点,则产生 2k+12k+1 的损失。求全部点的损失之和。

【Hint】

【提示】

线段 (0,0)(0,0)(x,y)(x,y) 的内部整点数量为 gcd(x,y)1\gcd(x,y)-1,因此单点贡献为 2gcd(x,y)12\gcd(x,y)-1。问题转化为矩形中的最大公约数之和。

【数据点 1∼61\sim 61∼6】

(0,0)(0,0)(x,y)(x,y) 的线段内部共有 gcd(x,y)1\gcd(x,y)-1 个整点,所以该点的传输损失为

2(gcd(x,y)1)+1=2gcd(x,y)1.2(\gcd(x,y)-1)+1=2\gcd(x,y)-1.

min(n,m)=1\min(n,m)=1,每个点的最大公约数均为 11,答案为 max(n,m)\max(n,m)

min(n,m)=2\min(n,m)=2,记 s=max(n,m)s=\max(n,m)。第一行贡献为 ss,第二行在另一个坐标为偶数时额外贡献 22,所以答案为

2s+2s2.2s+2\left\lfloor\dfrac{s}{2}\right\rfloor.

【数据点 7∼127\sim 127∼12】

直接枚举全部 n×mn\times m 个点,使用辗转相除法计算 gcd(x,y)\gcd(x,y),再累加 2gcd(x,y)12\gcd(x,y)-1

时间复杂度为 O(nmlogmin(n,m))\mathcal{O}(nm\log\min(n,m)),空间复杂度为 O(1)\mathcal{O}(1)。这一做法的瓶颈是逐点处理,而最大公约数相同的点对可以放在一起统计。

【数据点 13∼1913\sim 1913∼19】

这一档满足 n=mn=m。设

Φ(s)=i=1sφ(i).\Phi(s)=\sum_{i=1}^{s}\varphi(i).

[1,s]2[1,s]^2 中,最大公约数为 11 的有序点对数量为 2Φ(s)12\Phi(s)-1。其中,对每个 2ys2\leq y\leq s,满足 1x<y1\leq x<ygcd(x,y)=1\gcd(x,y)=1xxφ(y)\varphi(y) 个;交换两个坐标得到另一半,最后补上点 (1,1)(1,1)

枚举最大公约数 dd。将两个坐标同时除以 dd 后,最大公约数恰为 dd 的点对数量为

2Φ(nd)1.2\Phi\left(\left\lfloor\dfrac{n}{d}\right\rfloor\right)-1.

线性筛预处理 Euler 函数及其前缀和,再枚举 dd 计算贡献即可。

【正解一:倍数容斥】

r=min(n,m)r=\min(n,m),定义 fdf_d 为满足

1xn,1ym,gcd(x,y)=d1\leq x\leq n,\qquad 1\leq y\leq m,\qquad \gcd(x,y)=d

的有序点对数量。

两个坐标都能被 dd 整除的点对共有

ndmd\left\lfloor\dfrac{n}{d}\right\rfloor \left\lfloor\dfrac{m}{d}\right\rfloor

个,其中还包含最大公约数为 2d,3d,2d,3d,\ldots 的点对。因此从大到小枚举 dd,有

fd=ndmdk2kdrfkd.f_d=\left\lfloor\dfrac{n}{d}\right\rfloor \left\lfloor\dfrac{m}{d}\right\rfloor -\sum_{\substack{k\geq 2\\kd\leq r}}f_{kd}.

枚举顺序保证右侧状态均已求出。每个点对按照其最大公约数恰好归入一个 fdf_d,所以递推不会遗漏,也不会重复。

记全部最大公约数之和为 SS,则

S=d=1rdfd.S=\sum_{d=1}^{r}d f_d.

原问题的答案为

2Snm.2S-nm.

内层枚举总次数为 d=1rr/d\sum_{d=1}^{r}\lfloor r/d\rfloor。时间复杂度为 O(rlogr)\mathcal{O}(r\log r),空间复杂度为 O(r)\mathcal{O}(r)

【正解二:Möbius 反演】

定义 F(d)F(d) 为满足 dxd\mid xdyd\mid y 的有序点对数量,定义 f(d)f(d) 为最大公约数恰为 dd 的有序点对数量。于是

F(d)=ndmd=dkf(k).F(d)=\left\lfloor\dfrac{n}{d}\right\rfloor \left\lfloor\dfrac{m}{d}\right\rfloor =\sum_{d\mid k}f(k).

对倍数关系作 Möbius 反演,得到

f(d)=t=1r/dμ(t)F(dt).f(d)=\sum_{t=1}^{\lfloor r/d\rfloor}\mu(t)F(dt).

交换求和顺序,并令 k=dtk=dt,有

S=d=1rdf(d)=k=1rF(k)tkμ(t)kt.\begin{aligned} S &=\sum_{d=1}^{r}d f(d)\\ &=\sum_{k=1}^{r}F(k)\sum_{t\mid k}\mu(t)\dfrac{k}{t}. \end{aligned}

根据恒等式

φ(k)=tkμ(t)kt,\varphi(k)=\sum_{t\mid k}\mu(t)\dfrac{k}{t},

最终得到

S=k=1rφ(k)nkmk.S=\sum_{k=1}^{r}\varphi(k) \left\lfloor\dfrac{n}{k}\right\rfloor \left\lfloor\dfrac{m}{k}\right\rfloor.

线性筛预处理 Euler 函数后枚举 kk,再输出 2Snm2S-nm。时间复杂度与空间复杂度均为 O(r)\mathcal{O}(r)

【参考代码】

正式 STD 使用正解一。

#include <cstdio>#include <cstring>#include <algorithm>#define MAXN 100010using namespace std;int n,m,r;long long Ans=0,f[MAXN];void Solve() {    scanf("%d%d",&n,&m);    Ans=0;    r=min(n,m);    for (int i=r;i>=1;i--) {        f[i]=1ll*(n/i)*(m/i);        for (int j=2;i*j<=r;j++) {            f[i]-=(f[i*j]);        }        Ans+=1ll*2*i*f[i];    }    Ans-=1ll*n*m;    printf("%lld\n",Ans);}int main() {    int c,T;    scanf("%d%d",&c,&T);    while(T-->0) Solve();    return 0;}