[BZOJ2705] [SDOI2012] Longge的问题 [莫比乌斯反演&欧拉函数]

[ L i n k \frak{Link} Link]


∑ ( i , n ) \sum (i,n) (i,n) n ≤ 2 32 n\le2^{32} n232
所有小于 n n n 的数都可以对答案产生贡献,考虑利用 g c d gcd gcd 缩小数据范围
那么按照 g c d gcd gcd 分类?

( i , n ) = 1 (i,n)=1 (i,n)=1 的数有 ϕ ( n ) \phi(n) ϕ(n) 个。

( i , n ) = k (i,n)=k (i,n)=k 的数有几个?显然就是 ( i / k , n / k ) = 1 (i/k,n/k)=1 (i/k,n/k)=1 的数的个数 ϕ ( n / k ) \phi(n/k) ϕ(n/k)
但是只是这样还不够,因为我们要算的是贡献(
所以要求的应该是 k ⋅ ϕ ( n / k ) k\cdot\phi(n/k) kϕ(n/k)

于是只需要求 ∑ d ∣ n ( n / d ) ⋅ ϕ ( d ) \sum\limits_{d|n}(n/d)\cdot\phi(d) dn(n/d)ϕ(d)
ϕ ( d ) \phi(d) ϕ(d) 拆开继续化式子还可以进一步降低复杂度。


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
unsigned long long n, sq, ans, xsq;
unsigned long long phi(unsigned long long x)
{
	unsigned long long ret = x;
	xsq = 1ull * sqrt(1.0 * x);
	for (unsigned long long i = 2ull; i <= xsq; ++i)
	{
		if (x % i == 0) ret = ret / i * (i - 1);
		while (x % i == 0) x /= i;
	}
	return (x > 1ull) ? (ret / x * (x - 1ull)) : ret;
}
int main()
{
	scanf("%lld", &n);
	sq = 1ull * sqrt(1.0 * n);
	for (unsigned long long i = 1ull; i <= sq; ++i)
	{
		if (n % i == 0) 
		{
			ans += (n / i) * phi(i);
			if (i * i != n) ans += i * phi(n / i);
		}
	}
	printf("%lld", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值