传送门 设 f ( n ) = ∑ i = 1 n ∑ j = 1 n [ l c m ( i , j ) ≤ n ] f(n)=\sum_{i=1}^{n}\sum_{j=1}^n[lcm(i,j)\le n] f(n)=∑i=1n∑j=1n[lcm(i,j)≤n],题目让我们求的其实是 ∑ i = 1 b ∑ j = 1 i [ l c m ( i , j ) ≤ b ] − ∑ i = 1 a − 1 ∑ j = 1 i [ l c m ( i , j ) ≤ a − 1 ] \sum_{i=1}^b\sum_{j=1}^i[lcm(i,j)\le b]-\sum_{i=1}^{a-1}\sum_{j=1}^i[lcm(i,j)\le a-1] ∑i=1b∑j=1i[lcm(i,j)≤b]−∑i=1a−1∑j=1i[lcm(i,j)≤a−1],也就是说要求出 ∑ i = 1 n ∑ j = 1 i [ l c m ( i , j ) ≤ b ] \sum_{i=1}^n\sum_{j=1}^i[lcm(i,j)\le b] ∑i=1n∑j=1i[lcm(i,j)≤b],但这个式子不太方便我们反演,它其实就是 1 2 ( ∑ i = 1 n ∑ j = 1 n [ l c m ( i , j ) ≤ n ] + ∑ i = 1 n [ l c m ( i , i ) ≤ n ] ) = f ( n ) + n 2 \frac 12(\sum_{i=1}^n\sum_{j=1}^n[lcm(i,j)\le n]+\sum_{i=1}^n[lcm(i,i)\le n])=\frac {f(n)+n}2 21(∑i=1n∑j=1n[lcm(i,j)≤n]+∑i=1n[lcm(i,i)≤n])=2f(n)+n,因此我们下面考虑如何求出 f ( n ) f(n) f(n)。
f ( n ) = ∑ i = 1 n ∑ j = 1 n [ l c m ( i , j ) ≤ n ] = ∑ k = 1 n ∑ i = 1 n ∑ j = 1 n [ i j k ≤ n ] [ g c d ( i , j ) = k ] = ∑ k = 1 n ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ n k ⌋ [ i j k ≤ n ] ∑ d ∣ i , d ∣ j μ ( d ) = ∑ k = 1 n ∑ i = 1 n ∑ j = 1 n [ i j k ≤ n ] ∑ d ∣ i , d ∣ j μ ( d ) = ∑ d = 1 n μ ( d ) ∑ k = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ i j k ≤ ⌊ n d 2 ⌋ ] = ∑ d = 1 ⌊ n ⌋ μ ( d ) ∑ k = 1 ⌊ n d 2 ⌋ ∑ i = 1 ⌊ n d 2 ⌋ ∑ j = 1 ⌊ n d 2 ⌋ [ i j k ≤ ⌊ n d 2 ⌋ ] = ∑ d = 1 ⌊ n ⌋ μ ( d ) g ( ⌊ n d 2 ⌋ ) . . . . . 令 g ( n ) = ∑ k = 1 n ∑ i = 1 n ∑ j = 1 n [ i j k ≤ n ] \begin{aligned} f(n)&=\sum_{i=1}^n\sum_{j=1}^n[lcm(i,j)\le n]\\ &=\sum_{k=1}^n\sum_{i=1}^n\sum_{j=1}^n[\frac {ij}k\le n][gcd(i,j)=k]\\ &=\sum_{k=1}^n\sum_{i=1}^{\lfloor \frac nk\rfloor}\sum_{j=1}^{\lfloor\frac nk\rfloor}[ijk\le n]\sum_{d\mid i,d\mid j}\mu(d)\\ &=\sum_{k=1}^n\sum_{i=1}^{n}\sum_{j=1}^{n}[ijk\le n]\sum_{d\mid i,d\mid j}\mu(d)\\ &=\sum_{d=1}^n\mu(d)\sum_{k=1}^n\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac nd\rfloor}[ijk\le \lfloor\frac n{d^2}\rfloor]\\ &=\sum_{d=1}^{\lfloor\sqrt n\rfloor}\mu(d)\sum_{k=1}^{\lfloor \frac n{d^2}\rfloor}\sum_{i=1}^{\lfloor\frac n{d^2}\rfloor}\sum_{j=1}^{\lfloor\frac n{d^2}\rfloor}[ijk\le \lfloor\frac n{d^2}\rfloor]\\ &=\sum_{d=1}^{\lfloor\sqrt n\rfloor}\mu(d)g(\lfloor\frac n{d^2}\rfloor).....令g(n)=\sum_{k=1}^n\sum_{i=1}^n\sum_{j=1}^n[ijk\le n] \end{aligned} f(n)=i=1∑nj=1∑n[lcm(i,j)≤n]=k=1∑ni=1∑nj=1∑n[kij≤n][gcd(i,j)=k]=k=1∑ni=1∑⌊kn⌋j=1∑⌊kn⌋[ijk≤n]d∣i,d∣j∑μ(d)=k=1∑ni=1∑nj=1∑n[ijk≤n]d∣i,d∣j∑μ(d)=d=1∑nμ(d)k=1∑ni=1∑⌊dn⌋j=1∑⌊dn⌋[ijk≤⌊d2n⌋]=d=1∑⌊n ⌋μ(d)k=1∑⌊d2n⌋i=1∑⌊d2n⌋j=1∑⌊d2n⌋[ijk≤⌊d2n⌋]=d=1∑⌊n ⌋μ(d)g(⌊d2n⌋).....令g(n)=k=1∑ni=1∑nj=1∑n[ijk≤n] 现在考虑如何求 g ( n ) g(n) g(n),根据对称性,我们假设 k ≤ i ≤ j k\le i\le j k≤i≤j,于是容易确定 k ∈ [ 1 , ⌊ n 1 3 ⌋ ] , i ∈ [ k , ⌊ n k ⌋ ] , j ∈ [ i , ⌊ n i k ⌋ ] k\in[1,\lfloor n^{\frac 13}\rfloor],i\in[k,\lfloor \sqrt{\frac nk}\rfloor],j\in[i,\lfloor\frac n{ik}\rfloor] k∈[1,⌊n31⌋],i∈[k,⌊kn ⌋],j∈[i,⌊ikn⌋],枚举量大概是 O ( n + n 2 + n 3 + . . . + n n 1 3 ) = O ( ∫ 1 n 1 3 n x d x ) = O ( n 2 3 ) O(\sqrt n+\sqrt{\frac n2}+\sqrt{\frac n3}+...+\sqrt{\frac n{n^{\frac 13}}})=O(\int_{1}^{n^{\frac 13}} \sqrt{\frac nx}\, {\rm d}x)=O(n^{\frac 23}) O(n +2n +3n +...+n31n )=O(∫1n31xn dx)=O(n32),然后枚举的时候分三种情况计算贡献即可 k < i < j k<i<j k<i<j时要算6, k = i < j 或 k < i = j k=i<j或k<i=j k=i<j或k<i=j时要算3, k = i = j k=i=j k=i=j时要算1。
总复杂度的话就是 O ( ∑ d = 1 n ( n d 2 ) 2 3 ) = O ( n 2 3 ) O(\sum_{d=1}^{\sqrt n}{(\frac n{d^2})}^{\frac 23})=O(n^{\frac 23}) O(∑d=1n (d2n)32)=O(n32),你可以理解为杜教筛外面套了个 O ( n ) O(\sqrt n) O(n )的分块,因此复杂度不变。
int prim[maxn],tot,mu[maxn]; bool flag[maxn]; void init(int n){ mu[1]=1; FOR(i,2,n+1){ if(!flag[i])prim[tot++]=i,mu[i]=-1; for(register int j=0;j<tot && prim[j]*i<=n;++j){ flag[i*prim[j]]=1; if(i%prim[j]==0)break; mu[i*prim[j]]=-mu[i]; } } } ll get(ll n){ register int limt1 = pow(n,1.0/3.0),limt2; register ll ans=0,c,up; while(1ll*limt1*limt1*limt1<=n)limt1++; while(1ll*limt1*limt1*limt1>n)limt1--; FOR(k,1,limt1+1){ c=n/k; limt2=(int)(sqrt(c)+0.5); FOR(i,k,limt2+1){ up=c/i; if(up<i)break; if(i==k){ ans+=3ll*(up-i)+1ll; }else{ ans+=6ll*(up-i)+3ll; } } } return ans; } ll cal(ll n){ if(!n)return 0; register int limt = sqrt(n); register ll ans=0; FOR(i,1,limt+1)ans+=mu[i]*get(n/(1ll*i*i)); return (ans+n)>>1; } int main(){ ll a,b; rd(&a,&b); init((int)sqrt(b)); wrn(cal(b)-cal(a-1)); }