设 d ( x ) d(x) d(x)为 x x x的约数个数,给定 N N N、 M M M,求 ∑ i = 1 N ∑ j = 1 M d ( i j ) \sum^{N}_{i=1}\sum^{M}_{j=1} d(ij) i=1∑Nj=1∑Md(ij)
N , M , T < = 50000 N,M,T<=50000 N,M,T<=50000
首先很不显然的有这样一个结论:
d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[(x,y)==1] d(ij)=x∣i∑y∣j∑[(x,y)==1]
将一个数唯一质因数分解为 p 1 k 1 p 2 k 2 p 3 k 3 . . . p n k n p_1^{k_1}p_2^{k_2}p_3^{k_3}...p_n^{k_n} p1k1p2k2p3k3...pnkn,其约数个数为 ( k 1 + 1 ) ( k 2 + 1 ) ( k 3 + 1 ) . . . ( k n + 1 ) (k_1+1)(k_2+1)(k_3+1)...(k_n+1) (k1+1)(k2+1)(k3+1)...(kn+1)
考虑一个质数 p p p对 d ( i j ) d(ij) d(ij)的影响,假设 i i i分解质因数后有 k k k个 p p p, j j j分解质因数后有 q q q个 p p p,则产生的贡献即为 k + q + 1 k+q+1 k+q+1,接下来是关键的一步(反正我想不到XD)
k + q + 1 = ∑ x = 0 k ∑ y = 0 q [ ( p x , p y ) = = 1 ] k+q+1=\sum_{x=0}^k\sum_{y=0}^q[(p^x,p^y)==1] k+q+1=x=0∑ky=0∑q[(px,py)==1]
(此句可自行忽略:只有当 x y = 0 xy=0 xy=0时才会有值,这就相当于一个 ( k + 1 ) ∗ ( q + 1 ) (k+1)∗(q+1) (k+1)∗(q+1)的矩形,只取了左下角的 L L L字型的一块)
根据乘法原理,有
d ( i j ) = ∑ x 1 = 0 k 1 ∑ y 1 = 0 q 1 [ ( p 1 x 1 , p 1 y 1 ) = = 1 ] ∗ ∑ x 2 = 0 k 2 ∑ y 2 = 0 q 2 [ ( p 2 x 2 , p 2 y 2 ) = = 1 ] ⋅ ⋅ ⋅ ∗ ∑ x n = 0 k n ∑ y n = 0 q n [ ( p n x n , p n y n ) = = 1 ] d(ij)=\sum_{x_1=0}^{k_1}\sum_{y_1=0}^{q_1}[(p_1^{x_1},p_1^{y_1})==1]\newline *\sum_{x_2=0}^{k_2}\sum_{y_2=0}^{q_2}[(p_2^{x_2},p_2^{y_2})==1]\newline ···\newline *\sum_{x_n=0}^{k_n}\sum_{y_n=0}^{q_n}[(p_n^{x_n},p_n^{y_n})==1] d(ij)=x1=0∑k1y1=0∑q1[(p1x1,p1y1)==1]∗x2=0∑k2y2=0∑q2[(p2x2,p2y2)==1]⋅⋅⋅∗xn=0∑knyn=0∑qn[(pnxn,pnyn)==1]
因为必须满足所有 ( p n x n , p n y n ) = = 1 (p_n^{x_n},p_n^{y_n})==1 (pnxn,pnyn)==1才会对答案造成贡献,则可以变形为 ( ∏ i = 1 n p n x n , ∏ i = 1 n p n y n ) = = 1 (\prod_{i=1}^np_n^{x_n},\prod_{i=1}^np_n^{y_n})==1 (i=1∏npnxn,i=1∏npnyn)==1
所以 d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[(x,y)==1] d(ij)=x∣i∑y∣j∑[(x,y)==1]
(以上证明摘自:传送门)
现在就有了 A n s = ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = = 1 ] Ans=\sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}^{}\sum_{y|j}^{}[(x,y)==1] Ans=i=1∑Nj=1∑Mx∣i∑y∣j∑[(x,y)==1]
根据数论中切换枚举次序的套路以及莫比乌斯反演对布尔条件框的替换,我们得到
A n s = ∑ x = 1 N ∑ y = 1 M ⌊ N x ⌋ ⌊ M y ⌋ [ ( x , y ) = = 1 ] = ∑ x = 1 N ∑ y = 1 M ⌊ N x ⌋ ⌊ M y ⌋ ∑ k ∣ ( x , y ) μ ( k ) = ∑ k = 1 m i n ( N , M ) μ ( k ) ∑ k ∣ x ⌊ N x ⌋ ∑ k ∣ y ⌊ M y ⌋ = ∑ k = 1 m i n ( N , M ) μ ( k ) ∑ x = 1 ⌊ N k ⌋ ⌊ N k x ⌋ ∑ y = 1 ⌊ M k ⌋ ⌊ M k y ⌋ Ans=\sum_{x=1}^{N}\sum_{y=1}^{M}⌊\frac{N}{x}⌋⌊\frac{M}{y}⌋[(x,y)==1]\newline =\sum_{x=1}^{N}\sum_{y=1}^{M}⌊\frac{N}{x}⌋⌊\frac{M}{y}⌋\sum_{k|(x,y)}\mu(k)\newline =\sum_{k=1}^{min(N,M)}\mu(k)\sum_{k|x}^{}⌊\frac{N}{x}⌋\sum_{k|y}^{}⌊\frac{M}{y}⌋\newline =\sum_{k=1}^{min(N,M)}\mu(k)\sum_{x=1}^{⌊\frac{N}{k}⌋}⌊\frac{N}{kx}⌋\sum_{y=1}^{⌊\frac{M}{k}⌋}⌊\frac{M}{ky}⌋ Ans=x=1∑Ny=1∑M⌊xN⌋⌊yM⌋[(x,y)==1]=x=1∑Ny=1∑M⌊xN⌋⌊yM⌋k∣(x,y)∑μ(k)=k=1∑min(N,M)μ(k)k∣x∑⌊xN⌋k∣y∑⌊yM⌋=k=1∑min(N,M)μ(k)x=1∑⌊kN⌋⌊kxN⌋y=1∑⌊kM⌋⌊kyM⌋
于是这里使用分块优化,预处理 μ \mu μ的前缀和
最后考虑后面的两个Sigma怎么处理
可以观察发现它们都是 ∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^{n}⌊\frac{n}{i}⌋ ∑i=1n⌊in⌋的形式,此处可以用分块优化 Θ ( n n ) \Theta(n\sqrt{n}) Θ(nn)预处理
其实还可以 Θ ( n ) \Theta(n) Θ(n)预处理,可以发现 ∑ i = 1 n ⌊ n i ⌋ = ∑ i = 1 n ∑ i ∣ d n 1 \sum_{i=1}^{n}⌊\frac{n}{i}⌋=\sum_{i=1}^{n}\sum_{i|d}^{n}1 ∑i=1n⌊in⌋=∑i=1n∑i∣dn1
显然是约数个数和 d ( n ) d(n) d(n)的前缀和函数,于是线性筛出 μ ( n ) \mu(n) μ(n)与 d ( n ) d(n) d(n),求出前缀和即可
每次询问 Θ ( n ) \Theta(\sqrt{n}) Θ(n), 预处理 Θ ( n ) \Theta(n) Θ(n),总时间复杂度为 Θ ( n n ) \Theta(n\sqrt{n}) Θ(nn)
线性筛约数个数时存一下最小的质数 p 1 p_1 p1的次方 + 1 +1 +1,即存下 ( k 1 + 1 ) (k_1+1) (k1+1)就可以方便的线性筛了
线性筛约数和同理,存一下最小的质数 p 1 p_1 p1所对应的首项为 1 1 1,公比为 p 1 p_1 p1,项数为 k 1 + 1 k_1+1 k1+1的等比数列,即存下 ∑ i = 1 k 1 p 1 i \sum_{i=1}^{k_1}p_1^i ∑i=1k1p1i就可以愉快的线性筛了
#include
#include
#include
using namespace std;
const int MAXN = 100001;
namespace Mobius
{
#define LL long long
int Prime[MAXN], Cnt, mu[MAXN], d[MAXN], Minseq[MAXN];
bool IsnotPrime[MAXN];
LL sum_MU[MAXN], sum_D[MAXN];
void init()
{
mu[1] = d[1] = Minseq[1] = 1;
for(int i = 2; i < MAXN; ++i)
{
if(!IsnotPrime[i])
Prime[++Cnt] = i, mu[i] = -1, d[i] = Minseq[i] = 2;
for(int j = 1; j <= Cnt && i * Prime[j] < MAXN; ++j)
{
IsnotPrime[i * Prime[j]] = 1;
if(i % Prime[j] == 0)
{
Minseq[i * Prime[j]] = Minseq[i]+1;
mu[i * Prime[j]] = 0;
d[i * Prime[j]] = d[i] / Minseq[i] * Minseq[i * Prime[j]];
break;
}
Minseq[i * Prime[j]] = 2;
mu[i * Prime[j]] = -mu[i];
d[i * Prime[j]] = d[i]<<1;
}
}
for(int i = 1; i < MAXN; ++i)
sum_MU[i] = sum_MU[i-1] + mu[i],
sum_D[i] = sum_D[i-1] + d[i];
}
LL calc(int N, int M)
{
if(N > M) swap(N, M);
LL ret = 0;
for(int i = 1, j; i <= N; i=j+1)
{
j = min(N/(N/i), M/(M/i));
ret += (sum_MU[j]-sum_MU[i-1]) * sum_D[N/i] * sum_D[M/i];
}
return ret;
}
}
using namespace Mobius;
int main ()
{
init();
int T, n, m;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
printf("%lld\n", calc(n, m));
}
}