洛谷传送门
BZOJ传送门
题目描述
Longge的数学成绩非常好,并且他非常乐于挑战高难度的数学问题。现在问题来了:给定一个整数N,你需要求出 ∑gcd(i,N)(1≤i≤N) ∑ g c d ( i , N ) ( 1 ≤ i ≤ N ) 。
输入输出格式
输入格式:
一个整数,为 N N 。
输出格式:
一个整数,为所求的答案。
输入输出样例
输入样例#1:
6
输出样例#1:
15
说明
对于60%的数据,
对于100%的数据, 0<N≤232 0 < N ≤ 2 32
解题分析
今天考这道题脑抽了推了个奇奇妙妙的式子出来, 还是 O(N) O ( N ) 的……
更讽刺的是这道题几个月前就放在洛谷的to do list 里面了, 结果直到今天都没做……
O(N−−√) O ( N ) 枚举因数, O(N−−√) O ( N ) 算每个因数的 ϕ ϕ 。
总复杂度 O(N−−√+N−−√×log(N)) O ( N + N × l o g ( N ) )
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <vector>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define ll long long
std::vector <ll> fac;
ll ans, n;
void dvd(ll now)
{
ll bd = std::sqrt(now);
for (R int i = 1; i <= bd; ++i)
{
if(!(now % i))
{
fac.push_back(i);
if(now / i != i) fac.push_back(now / i);
}
}
}
IN ll calc(ll now)
{
ll ret = now;
ll bd = std::sqrt(now);
for (int i = 2; i <= bd; ++i)
{
if(!(now % i))
{
ret = ret * (i - 1) / i;
W (!(now % i)) now /= i;
}
}
if(now > bd) ret = ret * (now - 1) / now;
return ret;
}
int main(void)
{
scanf("%lld", &n);
dvd(n); int siz = fac.size();
for (R int i = 0; i < siz; ++i) ans += fac[i] * calc(n / fac[i]);
printf("%lld", ans);
}