总结 link
已知 (f(x) = displaystyle sum_{d|x}μ(d)∗d)
现在请求出下面式子的值
(displaystyle sum_{i=1}^n sum_{j=1}^nf(gcd(i,j))∗f(lcm(i,j)))
由于值可能过大所以请对 10^9+7 取模
(n≤10^9)
输入
一行一个整数 n
输出
一行一个数字,为问题描述所求的值
输入样例
4
输出样例
9
正解
看到 gcd 与 lcm 就想乘起来 , 得到 i * j , 考试时我也这么做了 , 结果也没写出来 。
考完之后听老师讲 , 才发现 f 不是完全积性函数 , 而 gcd 与 lcm 也不互质 , 心里一阵发慌。。。。。。
不过吧 , 正解就是 (f(gcd(i , j)) * f(lcm(i , j)) = f(i) * f(j)) 原因吧。。
把 i , j 质因数分解, 没有的就当成 0 次幂 。
gcd 就相当于 , 两者的指数取min , lcm 就相当于取 max , 设 两个指数分别是 c1 , c2;
那 (p^{c1} * p^{c2} = p^{max(c1 , c2) + min(c1 , c2)}) 瞎猫碰见了死耗子。。。。。。
这样就是 (ans = displaystyle {sum_{i=1}^nf(i)}^2)
[large{
egin{aligned}
ans =& sum_{i=1}^nsum_{j|i}j * mu(j) \
=&sum_{d=1}^nsum_{i=1}^{n/d}d * mu(d)\
=&sum_{d=1}^nd * mu(d) * (n/d) \
end{aligned}
}
]
(n / d) 可以整除分块 , 之后就是计算(d * mu(d)) 的前缀和
设 (g(x) = x * mu(x))
[large{
egin{aligned}
(g * id)(x) &= sum_{d|x}d * mu(d) * (n/d) \
&= sum_{d|x}mu(d) \
&= e
end{aligned}
}
]
很神奇吧 , 之后就是杜教筛的板子了 , 放代码
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
const int mod = 1e9+7 , N = 2e6 + 100 , maxn = 2e6;
#define int long long
int n , tot;
map<int,int> w;
int prime[N] , vis[N] , mu[N] , f[N];
void Init(int maxn)
{
mu[1] = 1;
for(int i = 2 ; i <= maxn ; ++i)
{
if(!vis[i]) prime[++tot] = i , mu[i] = -1;
for(int j = 1 ; j <= tot && i * prime[j] <= maxn ; ++j)
{
vis[i * prime[j]] = 1;
if(i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1 ; i <= maxn ; ++i) f[i] = (f[i-1] + mu[i] * i % mod) % mod;
return ;
}
int get(int n)
{
if(n <= maxn) return f[n];
if(w.count(n)) return w[n];
int res = 0;
for(int i = 2 , r ; i <= n ; i = r + 1)
{
r = min(n , n / (n / i));
res = (res + get(n / i) * ((i + r) * (r - i + 1) / 2) % mod) % mod;
}
res = ((1 - res) % mod + mod) % mod;
return w[n] = res;
}
signed main()
{
freopen("A.in" , "r" , stdin);
freopen("A.out" , "w" , stdout);
cin >> n; Init(2e6);
int ans = 0;
for(int i = 1 , r; i <= n ; i = r + 1)
{
r = min(n , n / (n / i));
ans = (ans + (get(r) - get(i-1) + mod) % mod * (n / i) % mod) % mod;
}
cout << ans * ans % mod << endl;
fclose(stdin); fclose(stdout); return 0;
}