积性函数
定理1.
算术函数f,对于任意两个互质的正整数n、m,都有f(m*n) = f(m) * f(n) ,f 叫做积性函数。
算术函数f,对于任意两个正整数n、m,都有f(m*n) = f(m) * f(n) ,f 叫做完全积性函数。
定理2.
如果f是积性函数,对于任意正整数n,根据算术基本定理n = *
*
*.............. *
那么f(n) = f( ) * f(
) * f(
)*.........* f(
)
定理3.
设p是素数,a是正整数,那么欧拉函数 =
—
证明:除了p的倍数之外,都与 互质,p的倍数的个数有
个
题目:51nod 1188 最大公约数之和V2。
给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和。
相当于计算这段程序(程序中的gcd(i,j)表示i与j的最大公约数):
G=0;
for(i=1;i<N;i++)
for(j=i+1;j<=N;j++)
{
G+=gcd(i,j);
}
Input
第1行:1个数T,表示后面用作输入测试的数的数量。(1 <= T <= 50000)
第2 - T + 1行:每行一个数N。(2 <= N <= 5000000)
Output
共T行,输出最大公约数之和。
题目相当于求 {2之内与2的最大公因数之和}+{3之内与3的最大公因数之和}+........+{N之内与N的最大公因数之和} ,注:N之内等包含本身。
(1).因为gcd(i , m*n)=gcd(i * m) * gcd(i * n) ,m,n互质,所以gcd是积性函数,积函数的求和函数也是积性函数。
(2).令f(n)= (1<=i<=N),易知 f(n)= sum( p *
) ,其中p 是 n 的因子。
解释 p * :
p * 表示为[1,N]中与N的最大公因子是p的贡献是p *
。
因为p是n的因子,n/p也是n的因子, n与 n/p 的 因子恰好等于 n 的因子,
[1, n/p]中与n/p互质的数 与 n同样 互质 ,[1, n/p] 中与 n/p互质的数与p相乘, 产生的 p的倍数与N的最大公因数是 p。所以N的因子p的贡献为 ,对N的所有因子使用这样的计算方法即得 f(n)。
依据积性函数的特点 :
n = *
*
*.............. *
,
f(n) = f( ) * f(
) * f(
)*.........* f(
),
如何求 f( ) : f(
)的所有因子贡献之和=
*
(
) +
*
(
) +...+
*
(
) ,
整理得:( * p -
+ p ) *
结合线性筛选,可以求解出[1,n] 的最大公因数之和的前缀和。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5000055;
bool vis[N];
int ans[N];
int tot;
ll GcdSum[N];
void getPrime(int n){
for(int i=2;i<=n;i++){
if(!vis[i]) {
ans[tot++]=i;
//质数之内与该质数的最大公因数之和
GcdSum[i]=i+i-1;
}
for(int j=0;j<tot&&ans[j]*i<=n;j++){
if(i%ans[j]!=0){
//ans[j],i互质
GcdSum[i*ans[j]]=GcdSum[i]*GcdSum[ans[j]];
}else{
//ans[j],i不互质,分解成f(n)=(p1^a1)*f(p2^a2).... 的形式求解
int r=1;
int k=i;
while(k%ans[j]==0){
r++;
k/=ans[j];
}
//f(p^r)=r*(p^r-p^(r-1))+p^r的稍微变形,以至于只需要求解一次幂。
GcdSum[i*ans[j]]=(ll)(pow(ans[j],r-1)+0.5)*((ans[j]-1)*r+ans[j])*GcdSum[k];
}
vis[ans[j]*i]=true;
if(i%ans[j]==0) break;
}
}
}
int main()
{
GcdSum[1]=1;
getPrime(N-1);
for(int i=0;i<N;i++){
//减去gcd(i,i)的情况
GcdSum[i]-=i;
//前缀和
GcdSum[i]+=GcdSum[i-1];
}
int t,n;
scanf("%d",&t);
for(int i=0;i<t;i++){
scanf("%d",&n);
printf("%lld\n",GcdSum[n]);
}
return 0;
}