前置技能;
(1)
gcd()函数是一个非完全积性函数,
(2)
∑gcd(i, N)也是一个积性函数,记为
,并且更一般地将N唯一分解。
有
其中,
(3)
(4)
下面求解
由(3)
注意到p^c 的约数d仅仅可能为p^k
并且有
.
化简得,
于是得到了下面这条key代码。
ll f(int p,int r)
{
return (r+1)*qpow(p, r)-r*qpow(p, r-1);
}
#include<stdio.h>
#include<iostream>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#define ms0(a) memset(a,0,sizeof(a))
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e6;
int n;
struct node{
int p,c;
}a[100];
//欧拉筛法( O(n) )
//p[]来存放已得到的素数,np为已得到的素数个数,p从 0 开始
int np=0,p[maxn],v[maxn+10];
int gg(int n){
for(int i=2;i<=n;i++){
if(!v[i]) p[++np]=i;//此时的i为某个质数
for(int j=1;j<=np && i*p[j]<=n;j++){
v[i*p[j]]=1; //用这个合数的最小质因子去筛掉这个合数
if(i%p[j]==0) break;
}
}
return np;
}
int cnt;
void fenjie(int n)
{
cnt=0;
for(int i=1;i<=np && n>=p[i];i++){
if(n%p[i]==0){
a[++cnt].p=p[i];
int ci=0;
while(n%p[i]==0){
ci++;
n/=p[i];
}
a[cnt].c=ci;
}
}
if(n>1){
a[++cnt].p=n;
a[cnt].c=1;
}
}
ll qpow(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=ans*a;
a=a*a;
n/=2;
}
return ans;
}
ll f(int p,int r)
{
return (r+1)*qpow(p, r)-r*qpow(p, r-1);
}
int main(){
gg(maxn);
while (~scanf("%d",&n))
{
ms0(a);
fenjie(n);
ll ans=1;
for(int i=1;i<=cnt;i++)
{
ans*=f(a[i].p,a[i].c);
}
printf("%lld\n",ans);
}
return 0;
}