题意:求
∑i=1n∑j=1nlcm(i,j)
题解:
原式可化为:
i=1∑nj=1∑ngcd(i,j)ij
i=1∑nj=1∑nd=1∑ndij[d=gcd(i,j)]
将i, 改为
id,j改为
jd:
d=1∑ndi=1∑⌊dn⌋ij=1∑⌊dn⌋j[gcd(i,j)=1]
引理1:
∑i=1ni[gcd(n,i)=1]=2nϕ(n)+[n=1]
理由如下:
由于对任意
gcd(n,i)=1,由辗转相除得:
gcd(n,n−i)=1
故
∑i=1ni[gcd(n,i)=1]=2nϕ(n)+[n=1]
继续化简:
若
i=j=1,则会被多算一次,故减1
若
i=j̸=n,则
gcd(i,j)̸=1,故不会被重复 计算
故
d=1∑nd(2i=1∑⌊dn⌋ij=1∑ij[gcd(i,j)=1]−1)
由引理1:
d=1∑nd(2i=1∑⌊dn⌋i2iϕ(i)+[i=1]−1)
当
i=1时,
2iϕ(i)+[i=1]=1
故
d=1∑ndi=1∑⌊dn⌋i2ϕ(i)
用杜教筛求
∑i=1⌊dn⌋i2ϕ(i):
令
g(x)=i=1∑ni2d=1∑i[d∣i]ϕ(d)
s(x)=i=1∑ni2ϕ(i)
由于
d=1∑i[d∣i]ϕ(d)=i
故
g(x)=i=1∑ni3=4n2(n+1)2
故
s(x)=g(x)−i=2∑xi2d=1∑i−1[d∣i]ϕ(d)
s(x)=g(x)−i=2∑xi2d=1∑⌊ix⌋dϕ(d)
s(x)=g(x)−i=2∑xi2s(⌊ix⌋)
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll long long
using namespace std;
const int mn = 5000005, mod = 1000000007, inv4 = 250000002, inv2 = 500000004, inv6 = 166666668;
map<ll, ll> s;
ll phi[mn], pri[mn];
int cnt;
bool vis[mn];
inline void init(int n)
{
phi[1] = 1;
for(int i = 2; i <= n; i++)
{
if(!vis[i])
phi[i] = i - 1, pri[++cnt] = i;
for(int j = 1; j <= cnt && pri[j] * i <= n; j++)
{
vis[pri[j] * i] = 1;
if(i % pri[j] == 0)
{
phi[pri[j] * i] = pri[j] * phi[i] % mod;
break;
}
phi[pri[j] * i] = (pri[j] - 1) * phi[i] % mod;
}
}
for(int i = 1; i <= n; i++)
phi[i] = phi[i] * i % mod * i % mod;
for(int i = 1; i <= n; i++)
phi[i] += phi[i - 1], phi[i] %= mod;
}
ll h(ll x)
{
x %= mod;
return x * (x + 1) % mod * (2ll * x % mod + 1) % mod * inv6 % mod;
}
ll S(ll n)
{
if(n <= mn - 5)
return phi[n];
if(s.find(n) != s.end())
return s[n];
ll ret = n % mod * (n % mod) % mod * ((n % mod + 1) % mod) % mod * ((n % mod + 1) % mod) % mod * inv4 % mod;
for(ll i = 2, las; i <= n; i = las + 1)
las = n / (n / i), ret -= (h(las) - h(i - 1)) % mod * S(n / i) % mod, ret = (ret % mod + mod) % mod;
return s[n] = ret;
}
int main()
{
ll n;
scanf("%lld", &n);
init(min(n, (ll)(mn - 5)));
ll ans = 0;
for(ll i = 1, las; i <= n; i = las + 1)
las = n / (n / i), ans += (i % mod + las % mod) % mod * (las - i + 1) % mod * inv2 % mod * S(n / i) % mod, ans %= mod;
printf("%lld\n", ans);
}