2020.1.17 小测

总结 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;
}
原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12207401.html