积性函数

积性函数

定理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 = p_{1}^{a_{1}}  *  p_{2}^{a_{2}}  *  p_{3}^{a_{3}}  *.............. * p_{s}^{a_{s}}  

那么f(n) =  f(  p_{1}^{a_{1}} ) *  f(  p_{2}^{a_{2}} )  *  f(p_{3}^{a_{3}})*.........*  f(p_{s}^{a_{s}}

定理3.

设p是素数,a是正整数,那么欧拉函数\varphi (p^{a}) = p^{a} —  p^{a-1}

证明:除了p的倍数之外,都与p^{a} 互质,p的倍数的个数有p^{a-1}

 

 

题目: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)= \sum gcd(i , N)   (1<=i<=N),易知 f(n)= sum( p * \varphi (n/p) ) ,其中p 是 n 的因子。

解释 p * \varphi (n/p) :

p * \varphi (n/p) 表示为[1,N]中与N的最大公因子是p的贡献是p * \varphi (n/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的贡献为 \varphi (n/p) ,对N的所有因子使用这样的计算方法即得 f(n)。

 

 

依据积性函数的特点 :

n = p_{1}^{a_{1}}  *  p_{2}^{a_{2}}  *  p_{3}^{a_{3}}  *.............. * p_{s}^{a_{s}}  , 

f(n) =  f(  p_{1}^{a_{1}} ) *  f(  p_{2}^{a_{2}} )  *  f(p_{3}^{a_{3}})*.........*  f(p_{s}^{a_{s}}),

如何求 f(  p_{1}^{a_{1}} ) :  f(  p_{1}^{a_{1}} )的所有因子贡献之和= p^{1}*\varphip_{1}^{a_{1}-1}) + p^{2}*\varphip_{1}^{a_{1}-2}) +...+    p^{a_{1}}*\varphip_{1}^{0} ) ,

整理得:( a_{1} * p  -  a_{1} +  p  )  *   p^{a_{1}-1}

 

结合线性筛选,可以求解出[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;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值