Crash的数字表格
前言
板题三号
题目
讲解
求 \(\sum_{i=1}^n\sum_{j=1}^m\frac{i*j}{\gcd(i,j)}\)
\(\sum_{i=1}^n\sum_{j=1}^m\sum_{d|i,d|j,\gcd(i/d,j/d)=1}\frac{i*j}{d}\)
\(\sum_{d=1}^{\min(n,m)}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1]*i*j\)
令 \(f(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)=1]*i*j\)
\(\sum_{d=1}^{\min(n,m)}\sum_{d|i}^n\sum_{d|j}^m\mu(d)i*j\)
\(\sum_{d=1}^{\min(n,m)}\mu(d)*d^2\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}i*j\)
令 \(g(n,m)=\sum_{i=1}^n\sum_{j=1}^mi*j=\frac{n*(n+1)}{2}*\frac{m*(m+1)}{2}\)
\(f(n,m)=\sum_{d=1}^{\min(n,m)}\mu(d)*d^2*g(n,m)\)
前半段可以用前缀和,然后可以数论分块,后面的 \(g(n,m)\) 可以 \(O(1)\) 算
然后我们代回最原始的式子
\(\sum_{d=1}^{\min(n,m)}d*f(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)\)
同样也是数论分块!
所以这道题就是数论分块套数论分块
代码
int s[MAXN],mu[MAXN],prime[MAXN],pn;
bool vis[MAXN];
void sieve(int x)
{
s[1] = mu[1] = 1;
for(register int i = 2;i <= x;++ i)
{
if(!vis[i]) prime[++pn] = i,mu[i] = -1;
for(int j = 1;j <= pn && i * prime[j] <= x;++ j)
{
vis[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
s[i] = (s[i-1] + 1ll * mu[i] * i * i % MOD + MOD) % MOD;
}
}
int g(int x,int y){return (1ll * x * (x+1) / 2 % MOD) * (1ll * y * (y+1) / 2 % MOD) % MOD;}
int f(int x,int y)
{
int ret = 0;
if(x > y) swap(x,y);
for(int l = 1,r;l <= x;l = r+1)
{
r = Min(x/(x/l),y/(y/l));
ret = (ret + 1ll * (s[r] - s[l-1]) * g(x/l,y/l)) % MOD;
}
return ret;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); m = Read();
if(n > m) swap(n,m);
sieve(n);
for(int l = 1,r;l <= n;l = r+1)
{
int L = n/l,R = m/l;
r = Min(n/L,m/R);
ans = (ans + 1ll * (r-l+1) * (l+r) / 2 % MOD * f(L,R)) % MOD;
}
Put((ans + MOD) % MOD);
return 0;
}