Lcm(a,b)表示a和b的最小公倍数,A(n)表示Lcm(n,i)的平均数(1 <= i <= n),
例如:A(4) = (Lcm(1,4) + Lcm(2,4) + Lcm(3,4) + Lcm(4,4)) / 4 = (4 + 4 + 12 + 4) / 4 = 6。
F(a, b) = A(a) + A(a + 1) + ...... A(b)。(F(a,b) = ∑A(k), a <= k <= b)
例如:F(2, 4) = A(2) + A(3) + A(4) = 2 + 4 + 6 = 12。
给出a,b,计算F(a, b),由于结果可能很大,输出F(a, b) % 1000000007的结果即可。
收起
输入2个数a,b,中间用空格分隔(1 <= a <= b <= 10^9)。
输出F(a, b) % 1000000007的结果。
1 100
122726
又因为
所以,设,很明显F(i)是积性函数,那么如果我们可以快速求出F(i)的前缀和,就可以在时间内求出B(n)了。求积性函数前缀和很容易想到杜教筛,
代码:
#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
const int inv6 = 166666668;
const int inv2 = 5e8 + 4;
map M;
int prime[maxn],mark[maxn];
ll phi[maxn];
void gettable(){
phi[1] = 1;
for(int i = 2;i < maxn;++i){
if(!mark[i]) prime[++prime[0]] = i,phi[i] = i - 1;
for(int j = 1;j <= prime[0] && i * prime[j] < maxn;++j){
mark[i * prime[j]] = 1;
if(i % prime[j] == 0){
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
for(int i = 2;i < maxn;++i) phi[i] = (phi[i - 1] + phi[i] * i % mod) % mod;
}
ll getsum(ll n){
if(n < maxn) return phi[n];
if(M[n]) return M[n];
ll sum = n * ((2 * n + 1) % mod) % mod * (n + 1) % mod * inv6 % mod,k;//n*(2*n+1)*(n+1)/6
for(ll i = 2;i <= n;i = k + 1){
k = n / (n / i);
sum = (sum - getsum(n / i) * (i + k) % mod * (k - i + 1) % mod * inv2 % mod)% mod;
}
return M[n] = (sum + mod) % mod;
}
ll cal(ll n){
ll res = n,k;
for(ll d = 1;d <= n;d = k + 1){
k = n / (n / d);
res = (res + getsum(n / d) * (k - d + 1) % mod) % mod;
}
return res * inv2 % mod;
}
int main(){
gettable();
ll a,b;
cin>>a>>b;
cout<<(cal(b) - cal(a - 1) + mod) % mod <