Description
给定正整数
n,m
。求
∑i=1n∑j=1mlcm(i,j)gcd(i,j)
Input
一行两个整数n,m。
Output
一个整数,为答案模 109+7 后的值。
Sample Input
5 4
Sample Output
424
HINT
数据规模:
1≤n,m≤5×105 ,共有 3 组数据。
题解
莫比乌斯反演,关键还是推式子的过程。
完成!
这个式子看似是四重循环,但是最后两个
∑
可以通过维护前缀和
O(1)
的计算答案,前面两重循环看似
O(n2)
,但是事实上复杂度用调和级数可证明为
O(nlnn)
。
My Code
/**************************************************************
Problem: 3561
User: infinityedge
Language: C++
Result: Accepted
Time:7924 ms
Memory:18872 kb
****************************************************************/
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <complex>
#define inf 0x3f3f3f3f
#define eps 1e-9
#define MAXN 500000
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll p[MAXN + 5]; int cnt, vis[MAXN + 5];
ll miu[MAXN + 5];
ll linear_shaker(){
vis[1] = 1; miu[1] = 1;
for(int i = 2; i <= MAXN; i ++){
if(!vis[i]){
p[++cnt] = i;
miu[i] = -1;
}
for(int j = 1; j <= cnt && i * p[j] <= MAXN; j ++){
if(i % p[j] == 0){
vis[i * p[j]] = 1;
miu[i * p[j]] = 0;
break;
}
vis[i * p[j]] = 1;
miu[i * p[j]] = -miu[i];
}
}
}
inline ll qpow(ll a, ll b){
ll ret = 1;
for(; b; b >>= 1, a = a * a % mod){
if(b & 1) ret = ret * a % mod;
}
return ret;
}
ll n, m;
ll a[500005], sum[500005];
ll ans = 0;
int main(){
linear_shaker();
scanf("%lld%lld", &n, &m);
if(n > m) swap(n, m);
for(int i = 1; i <= m; i ++) a[i] = 1;
for(ll d = 1; d <= n; d ++){
for(int i = 1; i <= m / d; i ++){
a[i] = a[i] * i % mod;
sum[i] = (sum[i - 1] + a[i]) % mod;
}
ll tmp = 0;
for(ll c = 1; c <= n / d; c ++){
tmp = (tmp + miu[c] * qpow(c, 2 * d) % mod * sum[n / d / c] % mod * sum[m / d / c] % mod) % mod;
}
ans = (ans + qpow(d, d) * tmp) % mod;
}
printf("%lld\n", ans);
return 0;
}