题解:
假设 n < m n < m n<m,一波化简: ∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ i = 1 n ∑ j = 1 m i ∗ j g c d ( i , j ) = ∑ d = 1 n ∑ i = 1 n ∑ j = 1 m i ∗ j d ∗ [ g c d ( i , j ) = d ] = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∗ [ g c d ( i , j ) = 1 ] \sum_{i = 1}^n\sum_{j = 1}^{m}lcm(i,j) = \sum_{i = 1}^n\sum_{j = 1}^{m}\frac{i * j}{gcd(i,j)} = \sum_{d = 1}^{n}\sum_{i = 1}^n\sum_{j = 1}^{m}\frac{i * j}{d}*[gcd(i,j) = d] =\sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m} {d}\rfloor} i * j * d*[gcd(i,j) = 1] i=1∑nj=1∑mlcm(i,j)=i=1∑nj=1∑mgcd(i,j)i∗j=d=1∑ni=1∑nj=1∑mdi∗j∗[gcd(i,j)=d]=d=1∑ni=1∑⌊dn⌋j=1∑⌊dm⌋i∗j∗d∗[gcd(i,j)=1]
设 : f ( d ) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∗ [ g c d ( i , j ) = d ] 设:f(d) = \sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor} i * j * d*[gcd(i,j) = d] 设:f(d)=d=1∑ni=1∑⌊dn⌋j=1∑⌊dm⌋i∗j∗d∗[gcd(i,j)=d]
令 F ( x ) = ∑ x ∣ d f ( d ) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∗ [ x ∣ g c d ( i , j ) ] = ∑ d = 1 n ∑ i = 1 ⌊ n x ∗ d ⌋ ∑ j = 1 ⌊ m x ∗ d ⌋ i ∗ j ∗ d ∗ x 2 令F(x) = \sum_{x | d} f(d) = \sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor} i * j * d*[x | gcd(i,j)] = \sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{x * d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{x * d}\rfloor} i * j * d * x ^2 令F(x)=x∣d∑f(d)=d=1∑ni=1∑⌊dn⌋j=1∑⌊dm⌋i∗j∗d∗[x∣gcd(i,j)]=d=1∑ni=1∑⌊x∗dn⌋j=1∑⌊x∗dm⌋i∗j∗d∗x2
反 演 一 下 : f ( d ) = ∑ d ∣ x μ ( x d ) ∗ F ( x ) 反演一下:f(d) = \sum_{d | x} \mu(\frac{x}{d}) * F(x) 反演一下:f(d)=d∣x∑μ(dx)∗F(x)
f ( 1 ) = ∑ x = 1 ⌊ n d ⌋ μ ( x d ) ∗ F ( x ) = ∑ d = 1 n d ∗ ∑ x = 1 ⌊ n d ⌋ x 2 ∗ μ ( x ) ∗ ∑ i = 1 ⌊ n d ∗ x ⌋ i ∑ j = 1 ⌊ m d ∗ x ⌋ j f(1) = \sum_{x = 1}^{\lfloor\frac{n}{d}\rfloor} \mu(\frac{x}{d}) * F(x)=\sum_{d = 1}^nd*\sum_{x = 1}^{\lfloor\frac{n}{d}\rfloor}x^2*\mu(x)*\sum_{i = 1}^{\lfloor\frac{n}{d * x}\rfloor}i\sum_{j = 1}^{\lfloor\frac{m}{d * x}\rfloor}j f(1)=x=1∑⌊dn⌋μ(dx)∗F(x)=d=1∑nd∗x=1∑⌊dn⌋x2∗μ(x)∗i=1∑⌊d∗xn⌋ij=1∑⌊d∗xm⌋j
到这一步已经可以两层分块 O ( n ) O(n) O(n)过掉这题 (准确来说是 O ( n 3 4 O(n^{\frac{3}{4}} O(n43)?)
这里为什么 x x x 的上界是 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor ⌊dn⌋:因为前面设了 f ( d ) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∗ [ g c d ( i , j ) = d ] f(d) = \sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor} i * j * d*[gcd(i,j) = d] f(d)=d=1∑ni=1∑⌊dn⌋j=1∑⌊dm⌋i∗j∗d∗[gcd(i,j)=d]
x x x是d的倍数,由于 i 上限是 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor ⌊dn⌋(这里假设 n < m n < m n<m),因此d的倍数最大到 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor ⌊dn⌋(准确的说是gcd(i,j)最大到 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor ⌊dn⌋), x x x 应该枚举到 ⌊ n d ⌋ \lfloor\frac{n}{d}\rfloor ⌊dn⌋
注意到最终式子里枚举了 d , x d,x d,x,产生了 d ∗ x d * x d∗x,可以令 T = d ∗ x d * x d∗x,枚举 T 和 d,然后可以线性筛优化一下,解决多组的情况。
注意第一层分块的时候右边界取 m i n ( m / ( m / i ) , n / ( n / i ) ) min(m / (m / i),n / (n / i)) min(m/(m/i),n/(n/i)),因为后面有一个 ⌊ ⌊ m d ⌋ x ⌋ \lfloor\frac{\lfloor\frac{m}{d}\rfloor}{x}\rfloor ⌊x⌊dm⌋⌋
代码:
#include
using namespace std;
const int mod = 20101009;
const int maxn = 1e7 + 10;
bool ispri[maxn];
int pri[maxn],mu[maxn];
typedef long long ll;
ll sum[maxn];
int n,m;
void sieve(int n) {
ispri[0] = ispri[1] = true;
pri[0] = 0;mu[1] = 1;
for(int i = 2; i <= n; i++) {
if(!ispri[i]) pri[++pri[0]] = i,mu[i] = -1;
for(int j = 1; j <= pri[0] && i * pri[j] <= n; j++) {
ispri[i * pri[j]] = true;
if(i % pri[j] == 0) {
mu[i * pri[j]] = 0;
break;
}
mu[i * pri[j]] = -mu[i];
}
}
sum[0] = 0;
for(int i = 1; i <= n; i++)
sum[i] = (sum[i - 1] + mu[i] * 1ll * i % mod * i % mod + mod) % mod;
}
ll cal(int n) {
return 1ll * (1 + n) * n / 2 % mod;
}
int main() {
sieve(10000000);
scanf("%d%d",&n,&m);
int l1,r1,l2,r2;
ll res = 0;
if(n > m) swap(n,m);
for(l1 = 1; l1 <= n; l1 = r1 + 1) {
r1 = min(n / (n / l1),m / (m / l1));
ll tmp = 0;
for(l2 = 1; l2 <= n / l1; l2 = r2 + 1) {
int p1 = n / l1,p2 = m / l1;
r2 = min(p1 / (p1 / l2),p2 / (p2 / l2));
tmp = (tmp + cal(p1 / l2) * cal(p2 / l2) % mod * ((sum[r2] - sum[l2 - 1] + mod) % mod) % mod) % mod;
}
res = (res + 1ll * (l1 + r1) * (r1 - l1 + 1) / 2 % mod * tmp % mod + mod) % mod;
}
printf("%lld\n",res);
return 0;
}