Description:
给定整数 n,求:
(sum_{i=1}^n sum_{d|i}GCD(d, frac{i}{d}))
保证答案在 long long 范围内。
Solution:
莫比乌斯反演qvq,生搬硬套
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#define R register
#define ll long long
namespace IO
{
template<class T>
void rea(T &x)
{
char ch=getchar();int f(0);x = 0;
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
x = f?-x:x;
}
template<class T>
T max(T a, T b) { return (a>b?a:b); }
template<class T>
T min(T a, T b) { return (a<b?a:b); }
}
using IO::rea;
using namespace std;
ll n, up, ans;
ll prime[5000005], tot, phi[5000005];
bool ban[5000005];
void getphi(ll p)
{
phi[1] = 1;
for(R int i = 2; i <= p; ++i)
{
if(!ban[i]) prime[++tot] = i, ban[i] = 1, phi[i] = i-1;
for(R int j = 1; j <= tot; ++j)
{
if(i*prime[j] > p) break;
ban[i*prime[j]] = 1;
if(i % prime[j] == 0)
{
phi[i*prime[j]] = phi[i]*prime[j];
break;
}
else phi[i*prime[j]] = phi[i]*phi[prime[j]];
}
}
for(R int i = 1; i <= p; ++i) phi[i] = phi[i-1]+phi[i];
}
int main()
{
freopen("divisors.in","r",stdin);
freopen("divisors.out","w",stdout);
using IO::max;using IO::min;
rea(n);
up = sqrt(n);
getphi(up);
int j;
for(R int i = 1; i <= up; i = j)
{
for(j=i+1; n/(1ll*i*i) == n/(1ll*j*j) && j<=up;j++);
ll temp = 0, u = n/(1ll*i*i);
for(R ll x = 1; x <= u; ++x)
{
ll r = u/(u/x);
temp += (u/x) * (min(r, u)-x+1);
x = r;
}
ans += (phi[j-1]-phi[i-1])*temp;
}
cout<<ans<<endl;
return 0;
}