利用欧拉函数解决最大公约数相关问题
2013-07-11 12:24
525 查看
一、欧拉函数与最大公约数
欧拉函数phi(i)表示在[1~i)中,与i互质的数的个数。
如要求1-n中所有数与n的最大公约数的和。
设count(x)为1-n中,与n的最大公约数为x的个数,即gcb(i,n)=x,i的个数。(gcb(x,y)为x和y的最大公约数)
这个count(x)怎么求呢?
有gcb(i,n)=x,则gcb(i/x,n/x)=1,(如果为k,k!=1,则gcb(i,n)=k*x)。
则count(x)=phi(n/x)。因为这些数既然与n/x互质,则将这些数乘以x,则得到的数肯定与n最大公约数为x。
这样,我们就将n以内与n互质的数的个数(欧拉函数),转换为与n最大公约数为x的个数。
二、欧拉函数与代码
在知道了欧拉函数这么强大之后,我们来看看怎么求它。
维基百科上:
若
则
。
例如
根据上面的公式,我们可以得到如下代码:
int euler(int n)
{
int i,m;
m = n;
for(i=2; i<(int)sqrt(n*1.0)+1; i++)
{
if(n%i == 0)
{
m = m/i*(i-1); //找到一个素数,也可以用m = m - m/i;即m = m*(1-1/i);
while(n%i == 0) //保证上一步找到的都是素数
n /= i;
}
}
if(n>1)
m = m/n*(n-1);
return m;
}
或者这样:
#define maxn 1000
int phi[maxn];
void euler()
{
int i,j;
for(i=1;i<maxn;i++) phi[i]=i;
for(i=2;i<maxn;i++)
if(phi[i]==i) //判断是否为素数
for(j=i;j<maxn;j+=i)
phi[j]=phi[j]/i*(i-1); //对每个数组元素,处理掉i这个素数
}
欧拉函数是积性函数,即是说若m,n互质,
。
欧拉定律:
对任何两个互质的正整数a, m(即 gcd(a,m) = 1),
,有
当m是质数p时,此式则为:
即费马小定理。
三、相关问题
1、给出一个n(n<=10^9),求1-n这n个数,同n的最大公约数的和。比如:n = 6
1,2,3,4,5,6 同6的最大公约数分别为1,2,3,2,1,6,加在一起 = 15
根据第一节的分析,可以直接得到如下代码(从网上copy的):
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define N 1000005
typedef long long LL;
bool prime
;
LL p
;
LL k=0;
void isprime()
{
LL i,j;
memset(prime,true,sizeof(prime));
for(i=2;i<N;i++)
{
if(prime[i])
{
p[k++]=i;
for(j=i+i;j<N;j+=i)
{
prime[j]=false;
}
}
}
}
LL phi(LL n)
{
LL rea=n,i;
for(i=0;p[i]*p[i]<=n;i++)
{
if(n%p[i]==0)
{
rea=rea-rea/p[i];
while(n%p[i]==0) n/=p[i];
}
}
if(n>1)
rea=rea-rea/n;
return rea;
}
int main()
{
LL i,n,ans;
isprime();
while(cin>>n)
{
ans=0;
for(i=1;i*i<=n;i++)
{
if(i*i==n)
ans+=i*phi(n/i);
else if(n%i==0)
ans+=i*phi(n/i)+(n/i)*phi(i);
}
cout<<ans<<endl;
}
return 0;
}
2、求1-n中所有数的最大公约数之和
网上找到的凉粉代码,
代码1:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
#include<ctime>
using namespace std;
#define maxn 1000005
#define LL long long
int phi[maxn];
LL sumphi[maxn];
void Init()
{
int i,j;
memset(sumphi,0,sizeof(sumphi));
for(i=1;i<maxn;i++) phi[i]=i;
for(i=2;i<maxn;i++)
if(phi[i]==i)
for(j=i;j<maxn;j+=i)
phi[j]=phi[j]/i*(i-1);
for(i=1;i<maxn;i++)
sumphi[i]=sumphi[i-1]+phi[i];
}
int main()
{
Init();
int t,n,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
LL G=0;
for(i=1;i<=n;i++)
G+=i*(sumphi[n/i]-1); //计算每个最大公约数d出现的次数
printf("%lld\n",G);
}
return 0;
}
代码2:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
#include<ctime>
using namespace std;
#define maxn 1000005
#define LL __int64
int phi[maxn];
LL ans[maxn]; //ans[x]=sum(ans[i]*j); (i*j=x)
void Init()
{
int i,j,k;
for(i=2;i<maxn;i++) phi[i]=i;
for(i=2;i<maxn;i++)
if(phi[i]==i)
for(j=i;j<maxn;j+=i)
phi[j]=phi[j]/i*(i-1);
for(i=2;i<maxn;i++)
ans[i]=phi[i];
for(i=2;i<=1000;i++)
{
ans[i*i]+=phi[i]*i;
for(j=i*i+i,k=i+1;j<maxn;j+=i,k++)
ans[j]+=i*phi[k]+k*phi[i]; //i*k=j,预处理出i,k可以作为哪些数j的最大公约数
}
for(i=1;i<maxn;i++)
ans[i]+=ans[i-1];
}
int main()
{
Init();
int n;
while(scanf("%d",&n),n)
printf("%I64d\n",ans
);
return 0;
}
欧拉函数phi(i)表示在[1~i)中,与i互质的数的个数。
如要求1-n中所有数与n的最大公约数的和。
设count(x)为1-n中,与n的最大公约数为x的个数,即gcb(i,n)=x,i的个数。(gcb(x,y)为x和y的最大公约数)
这个count(x)怎么求呢?
有gcb(i,n)=x,则gcb(i/x,n/x)=1,(如果为k,k!=1,则gcb(i,n)=k*x)。
则count(x)=phi(n/x)。因为这些数既然与n/x互质,则将这些数乘以x,则得到的数肯定与n最大公约数为x。
这样,我们就将n以内与n互质的数的个数(欧拉函数),转换为与n最大公约数为x的个数。
二、欧拉函数与代码
在知道了欧拉函数这么强大之后,我们来看看怎么求它。
维基百科上:
若
则
。
例如
根据上面的公式,我们可以得到如下代码:
int euler(int n)
{
int i,m;
m = n;
for(i=2; i<(int)sqrt(n*1.0)+1; i++)
{
if(n%i == 0)
{
m = m/i*(i-1); //找到一个素数,也可以用m = m - m/i;即m = m*(1-1/i);
while(n%i == 0) //保证上一步找到的都是素数
n /= i;
}
}
if(n>1)
m = m/n*(n-1);
return m;
}
或者这样:
#define maxn 1000
int phi[maxn];
void euler()
{
int i,j;
for(i=1;i<maxn;i++) phi[i]=i;
for(i=2;i<maxn;i++)
if(phi[i]==i) //判断是否为素数
for(j=i;j<maxn;j+=i)
phi[j]=phi[j]/i*(i-1); //对每个数组元素,处理掉i这个素数
}
欧拉函数是积性函数,即是说若m,n互质,
。
欧拉定律:
对任何两个互质的正整数a, m(即 gcd(a,m) = 1),
,有
当m是质数p时,此式则为:
即费马小定理。
三、相关问题
1、给出一个n(n<=10^9),求1-n这n个数,同n的最大公约数的和。比如:n = 6
1,2,3,4,5,6 同6的最大公约数分别为1,2,3,2,1,6,加在一起 = 15
根据第一节的分析,可以直接得到如下代码(从网上copy的):
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define N 1000005
typedef long long LL;
bool prime
;
LL p
;
LL k=0;
void isprime()
{
LL i,j;
memset(prime,true,sizeof(prime));
for(i=2;i<N;i++)
{
if(prime[i])
{
p[k++]=i;
for(j=i+i;j<N;j+=i)
{
prime[j]=false;
}
}
}
}
LL phi(LL n)
{
LL rea=n,i;
for(i=0;p[i]*p[i]<=n;i++)
{
if(n%p[i]==0)
{
rea=rea-rea/p[i];
while(n%p[i]==0) n/=p[i];
}
}
if(n>1)
rea=rea-rea/n;
return rea;
}
int main()
{
LL i,n,ans;
isprime();
while(cin>>n)
{
ans=0;
for(i=1;i*i<=n;i++)
{
if(i*i==n)
ans+=i*phi(n/i);
else if(n%i==0)
ans+=i*phi(n/i)+(n/i)*phi(i);
}
cout<<ans<<endl;
}
return 0;
}
2、求1-n中所有数的最大公约数之和
网上找到的凉粉代码,
代码1:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
#include<ctime>
using namespace std;
#define maxn 1000005
#define LL long long
int phi[maxn];
LL sumphi[maxn];
void Init()
{
int i,j;
memset(sumphi,0,sizeof(sumphi));
for(i=1;i<maxn;i++) phi[i]=i;
for(i=2;i<maxn;i++)
if(phi[i]==i)
for(j=i;j<maxn;j+=i)
phi[j]=phi[j]/i*(i-1);
for(i=1;i<maxn;i++)
sumphi[i]=sumphi[i-1]+phi[i];
}
int main()
{
Init();
int t,n,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
LL G=0;
for(i=1;i<=n;i++)
G+=i*(sumphi[n/i]-1); //计算每个最大公约数d出现的次数
printf("%lld\n",G);
}
return 0;
}
代码2:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
#include<ctime>
using namespace std;
#define maxn 1000005
#define LL __int64
int phi[maxn];
LL ans[maxn]; //ans[x]=sum(ans[i]*j); (i*j=x)
void Init()
{
int i,j,k;
for(i=2;i<maxn;i++) phi[i]=i;
for(i=2;i<maxn;i++)
if(phi[i]==i)
for(j=i;j<maxn;j+=i)
phi[j]=phi[j]/i*(i-1);
for(i=2;i<maxn;i++)
ans[i]=phi[i];
for(i=2;i<=1000;i++)
{
ans[i*i]+=phi[i]*i;
for(j=i*i+i,k=i+1;j<maxn;j+=i,k++)
ans[j]+=i*phi[k]+k*phi[i]; //i*k=j,预处理出i,k可以作为哪些数j的最大公约数
}
for(i=1;i<maxn;i++)
ans[i]+=ans[i-1];
}
int main()
{
Init();
int n;
while(scanf("%d",&n),n)
printf("%I64d\n",ans
);
return 0;
}
相关文章推荐
- 利用辗转相除法来解决最大公约数问题
- 使用三种算法解决从键盘输入两个整数,输出两个整数的最大公约数的问题
- 利用"线段树"相关算法解决有关数组的问题[待续]
- 利用最大公约数求解问题
- 利用动态规划解决实际问题之多次兑换获取最大外汇收益
- 利用javascript解决相关的数组问题
- 利用ajax在index页面自动执行方法并显示相关内容,在执行相关按钮操作(如登录注册)后返回index页面后ajax不执行,无法显示相关内容的问题解决方法之一
- 如何利用企业移动应用来解决当今的最大问题?
- 利用匈牙利算法&Hopcroft-Karp算法解决二分图中的最大二分匹配问题
- 利用数组作参数求最大值(感觉学了数组能很快的解决问题)
- 利用匈牙利算法&Hopcroft-Karp算法解决二分图中的最大二分匹配问题 例poj 1469 COURSES
- 利用“栈”解决“出轨”问题
- 利用小数解析差异解决浏览器兼容性问题
- benchmark pm2的cluster模式发布web app的性能与相关问题解决方法
- 如何利用URIEncoding和useBodyEncodingForURI解决tomcat中文乱码问题
- Hibernate延迟加载以及利用Spring事务完美解决延迟加载问题
- 利用WebBrowser彻底解决Web打印问题(包括后台打印)
- PostgreSQL应用相关问题解决
- [导入]利用.NET的XML序列化解决系统配置问题
- quagga 安装详解以及相关问题解决