1.欧拉函数:
关于欧拉函数,求的是指不超过n的与n互素的正整数的个数,按一般思想就是对数n进行素因子分解之后,所有的素数幂的欧拉函数之积
定理:设p是一个素数,a是正整数,那么 φ (p^a)=p^a-p^(a-1)
推论:若n是奇数,φ(2n)=φ(n)
两个常用定理:
欧拉定理:对任何两个互质的正整数a,m(m>=2)有a^φ(m)≡1(mod m)
费马小定理:当m是质数的时候,a^(m-1)≡1(mod m)
欧拉函数的算法实现:
//递归求欧拉
#include <stdio.h>
#define maxn 10000
int phi[maxn];
//个人觉得这个时间比较慢,
//而且你懂的,数组的大小是有限的,
//如果是求大数的就不行了
void Phi()
{
for(int i=1;i<=maxn;i++)
phi[i]=i;
for(int i=2;i<=maxn;i+=2)
phi[i]/=2;
for(int i=3;i<=maxn;i+=2)
if(phi[i]==i)
for(int j=i;j<=maxn;j+=i)
phi[j]=phi[j]/i*(i-1);
}
然后是一种单独求欧拉值的:
//单独求欧拉函数
#include <stdio.h>
#include <math.h>
//如果必要,可以改成long long
unsigned euler(unsigned x)
{
unsigned i,res=x;
for(i=2;i<=sqrt(x*1.0);i++)
if(x%i==0)
{
res=res/i*(i-1);
while(x%i==0)
x/=i;
}
if(x>1)
res=res/x*(x-1);
return res;
}
还有一种素数表实现欧拉值的写法:
//传说这貌似时间最少
//用是时间是O(n) n是sqrt(x)内的素数的个数
//写起来好像跟前面的没什么很大的区别
#include <stdio.h>
#include <string.h>
int prime[50000];
int p[20000];
void Prime()
{
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(int i=2;i*i<=50000;i++)
if(prime[i])
for(int j=2*i;j<=50000;j+=i)
prime[j]=0;
int k=0;
for(int i=0;i<=50000;i++)
{
if(prime[i])
p[++k]=i;
}
}
int phi(int n)
{
int res=n;
for(int i=1;p[i]*p[i]<=n;i++)
if(n%p[i]==0)
{
res=res-res/p[i];
do
n/=p[i];
while(n%p[i]==0);
}
if(n>1)
res=res-res/n;
return res;
}
欧拉函数的应用:
http://poj.org/problem?id=2407
就是模板题,直接求出欧拉值
水题
#include <stdio.h>
long long euler(long long x)
{
long long i,res=x;
for(i=2;i*i<=x;i++)
if(x%i==0)
{
res=res/i*(i-1);
while(x%i==0)
x/=i;
}
if(x>1)
res=res/x*(x-1);
return res;
}
int main()
{
long long n;
while(scanf("%I64d",&n)!=EOF,n)
{
printf("%I64d\n",euler(n));
}
return 0;
}
http://poj.org/problem?id=1284
求原根
所谓原根指的是http://zh.wikipedia.org/wiki/原根 反正是不好玩的东西
#include <stdio.h>
int euler(int x)
{
int i,res=x;
for(i=2;i*i<=x;i++)
{
if(x%i==0)
{
res=res/i*(i-1);
while(x%i==0)
x/=i;
}
}
if(x>1)
res=res/x*(x-1);
return res;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
printf("%d\n",euler(n-1));
}
return 0;
}
http://poj.org/problem?id=2478
还是欧拉函数的应用,求的是从2到n的欧拉值之和
这个题REWA TLE MLE 多次。。。RE是因为没有注意到数据类型,数组开大了就MLE了,然后换了筛素数的方法求欧拉值结果WA了,改对之后又是RE了 唉 伤不起啊 给一个水题坑死了
算了 坑就坑吧 把试过的几次代码都贴上
//这个时间用了235ms
#include <cstdlib>
#include <iostream>
using namespace std;
#define maxn 1000001
long long a[maxn];
int main()
{
long long i,j;
for(i=1;i<=maxn;i++) a[i]=i;
for(i=2;i<=maxn;i+=2) a[i]/=2;
for(i=3;i<=maxn;i+=2) if(a[i]==i)
{
for(j=i;j<=maxn;j+=i)
a[j]=a[j]/i*(i-1);
}
for(i=3;i<maxn;i++)
a[i]+=a[i-1];
long long n;
while(cin>>n&&n)
cout<<a[n]<<endl;
return 0;
}
//这个时间用了79ms
#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 1000001
bool isprime[maxn];
long long prime[maxn];
long long phi[maxn];
long long ans[maxn];
void getprime()
{
long long k=0;
for(int i=0;i<=maxn;i++)
isprime[i]=1;
for(int i=2;i<=maxn;i++)
{
if(isprime[i])
{
prime[k++]=i;
phi[i]=i-1;
}
for(int j=0;j<k&′[j]*i<=maxn;j++)
{
isprime[i*prime[j]]=0;
if(i%prime[j]!=0)
{
phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
else
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
}
}
int main()
{
getprime();
ans[1]=0;
for(int i=2;i<=maxn;i++)
ans[i]=ans[i-1]+phi[i];
int n;
while(scanf("%d",&n),n)
{
printf("%I64d\n",ans[n]);
}
return 0;
}
//这个用了94ms
#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 1000001
bool isprime[maxn];
long long prime[maxn];
long long phi[maxn];
long long ans[maxn];
void getprime()
{
long long k=0;
for(int i=0;i<=maxn;i++)
isprime[i]=1;
for(int i=2;i<=maxn;i++)
{
if(isprime[i])
{
prime[k++]=i;
phi[i]=i-1;
}
for(int j=0;j<k&′[j]*i<=maxn;j++)
{
isprime[i*prime[j]]=0;
if(i%prime[j]!=0)
{
phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
else
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
}
}
int main()
{
getprime();
ans[1]=0;
for(int i=2;i<=maxn;i++)
ans[i]=ans[i-1]+phi[i];
int n;
while(scanf("%d",&n),n)
{
printf("%I64d\n",ans[n]);
}
return 0;
}
http://poj.org/problem?id=3090
根据理解将平面划分为两个区域,中间那一线的当然只看得到最近的点(1,1) 至于其他的就只看得到,与输入的n值所互质的数的个数,总的意思还是求1到n的欧拉值之和
#include <stdio.h>
#define maxn 10000
int phi[maxn];
int main()
{
for(int i=1;i<=maxn;i++)
phi[i]=i;
for(int i=2;i<=maxn;i+=2)
phi[i]/=2;
for(int i=3;i<=maxn;i+=2)
{
if(phi[i]==i)
{
for(int j=i;j<=maxn;j+=i)
phi[j]=phi[j]/i*(i-1);
}
}
for(int i=2;i<=maxn;i++)
phi[i]+=phi[i-1];
int n,t;
scanf("%d",&t);
int tt=0;
while(t--)
{
scanf("%d",&n);
printf("%d %d %d\n",++tt,n,2*phi[n]+1);
}
return 0;
}