数论 欧拉函数
就是对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n) 。
欧拉函数的通式:φ(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)……(1-1/pn)
其中p1, p2……pn为n的所有质因数,n是不为0的整数。φ(1)=1(唯一和1互质的数就是1本身)。
代码实现如下:
sum=n;
for(i=2;i<=n/i;i++)
{
if(n%i==0)
{
sum=sum/i*(i-1);
while(n%i==0)
n/=i;
}
}
if(n>1)
sum=sum/n*(n-1);
当然,在计算机中欧拉函数常用的还有欧拉打表:(就和素数打表性质差不多)
代码实现如下:
void init()//打表
{
int i,j,z;
for(i=0;i<maxx;i++)
{
s[i]=i;
}
for(i=2;i<maxx;i++)
{
if(s[i]==i)
{
for(j=i;j<maxx;j+=i)
{
s[j]=s[j]/i*(i-1);
}
}
}
for(i=2;i<maxx;i++)
{
s[i]=s[i-1]+s[i]*s[i];
}
}
其中最后一个for循环是求欧拉数组的前缀和
例题一:题目链接
题意:给你一个数n,请求出该数的欧拉值。
也就是运用模板一
代码:
//欧拉函数
/*
欧拉函数通式:
s(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)...(1-1/pn)
p1,p2,p3...pn是n的所有质因数,有s(1)=1(就是他本身)
*/
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string.h>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int main()
{
int i,j,z,n,sum;
while(~scanf("%d",&n))
{
if(n==0)
break;
sum=n;
for(i=2;i<=n/i;i++)
{
if(n%i==0)
{
sum=sum/i*(i-1);
while(n%i==0)
n/=i;
}
}
if(n>1)
sum=sum/n*(n-1);
printf("%d\n",sum);
}
return 0;
}
例题二:题目链接
题意:给你两个数a和b,请求出a到b之间所有欧拉值之和;
也就是进行欧拉打表
要注意,本题数据比较大,要开unsigned long long。
代码:
/*
需要对欧拉值进行打表
*/
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string.h>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
typedef unsigned long long ll;
const int maxx=5000010;
ll s[maxx];
void init()//打表
{
int i,j,z;
for(i=0;i<maxx;i++)
{
s[i]=i;
}
for(i=2;i<maxx;i++)
{
if(s[i]==i)
{
for(j=i;j<maxx;j+=i)
{
s[j]=s[j]/i*(i-1);
}
}
}
for(i=2;i<maxx;i++)
{
s[i]=s[i-1]+s[i]*s[i];
}
}
int main()
{
int i,j,z,k=0,t,a,b;
init();
scanf("%d",&t);
while(t--)
{
k++;
scanf("%d%d",&a,&b);
ll num=s[b]-s[a-1];
printf("Case %d: %llu\n",k,num);
}
return 0;
}