题意:求1~n任意俩数之间的最大公因数和;
代码如下:
# include <iostream>
# include <algorithm>
using namespace std;
typedef long long ll;
const int N=4000005;
bool prime[N],vis[N];
int pre[N];
int ph[N];
ll s[N];
void init()
{
prime[1]=false;
for(int i=2;i<=N;i++)
{
prime[i]=true;
}
int cnt=0;
for(int i=2;i<=N;i++)
{
if(prime[i])
{
pre[cnt++]=i;
ph[i]=i-1;
}
for(int j=0;pre[j]*i<=N&&j<cnt;j++)
{
prime[i*pre[j]]=false;
if(i%pre[j]==0)
{
ph[i*pre[j]]=ph[i]*pre[j];
break;
}
else
{
ph[i*pre[j]]=ph[i]*(pre[j]-1);
}
}
for(int j=1;j*i<=N;j++)
{
s[i*j]+=ph[i]*j;
}
}
}
int main()
{
int n;
init();
for(int i=1;i<=N;i++)
{
s[i]+=s[i-1];
}
while(cin>>n)
{
if(n==0)
{
break;
}
cout<<s[n]<<endl;
}
}
思路:利用欧拉函数性质;
欧拉函数:就是对于一个正整数n,小于n且和n互质的正整数(包括1)的个数;
公式:欧拉函数的通式:φ(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)……(1-1/pn)
其中p1,p2,p3,p4为n的质因数;
例子:2,3的最大公因数为1;
则4,6的最大公因数为2;
2之前的质数个数为1,2;
则1,2与j的最大公因数之和为ph[2]*j;
ph[i]数组的意思为欧拉函数n的求值;
本代码采用欧拉筛选素数打表欧拉函数
原理为:
当i为质数时当前值为i-1;
当i不为质数时分俩种情况;
1:i%prime[j]==0;
则prime[j]为i*prime[j]的最小质因子;
并且也为i的最小质因子;
则ph[i*prime[i]与ph[i]只相差prime[j]倍;
2:i%prime[j]!=0;
同上;
只不过prime[j]不是i的最小质因子数;
故ph[i*prime[j]与ph[i]除了相差primep[j]倍,还相差1/1-prime[j];