因为要学一下欧拉函数。。就找了一些题,然后发现了这道
题意很简单。。。就是求欧拉函数的值
首先 欧拉函数是什么。。欧拉函数是一个函数(虽然有些废话),传入一个参数,会给你一个经过函数处理完毕的数值
欧拉函数 F(x) 处理结果 等于 小于x的与x互质的个数
计算方式很简单: F(x) = x (1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn), 其中p1, p2……pn为 x 的所有质因数
那么计算方式 我们就可以化简, F(x) = x * (1-p1) /p1 * (1-p2)/p2 ......... 以此类推
对了 欧拉函数还有一些性质的:
1.f(n) = f(p1^a1) * f(p2^a2)……这步对于我们求欧拉函数很关键 即 对于两个互素整数m,n f(m*n) = f(m)*f(n)
2.当n为奇数时,有phi(2n)=phi(n);
3.设n为一大于2的正整数,则phi(n)为偶数
有以下几种求欧拉函数的方法
(1)直接求解,从1遍历到根号n,找出素因子,套入公式,接着将该素因子全部除去,最后判断n是否本身就是素数。
(太暴力了 就先不写了)
(2)筛法求出素数表,除去筛的时间,其复杂度变为o(x),x为小于n的素数个数
(3)递推求欧拉函数,适合于多次运用事先打表的情况,复杂度为o(nlnn)
打表的方法 简单的代码实现一下
void Init()
{
euler[1]=1;
for(int i=2;i<maxn;i++)
euler[i]=i;
for(int i=2;i<maxn;i++)
if(euler[i]==i)
for(int j=i;j<maxn;j+=i) //这段和素数筛很像
euler[j]=euler[j] *(i-1)/i ;
}
网上有一个大牛他的方法我感觉也很不错 思路我也写下来了
附大牛博客链接:https://blog.csdn.net/ctrss/article/details/51184407
开始令i的欧拉函数值等于它本身,如果i为偶数,可以利用定理二变为求奇数的。
若p是一个正整数满足,那么p是素数,在遍历过程中如果遇到欧拉函数值等于自身的情况,那么
说明该数为素数。把这个数的欧拉函数值改变,同时也把能被该素因子整除的数改变。
void phi()
{
for(int i=1; i<N; i++) p[i] = i;
for(int i=2; i<N; i+=2) p[i] >>= 1;
for(int i=3; i<N; i+=2)
{
if(p[i] == i)
{
for(int j=i; j<N; j+=i)
p[j] = p[j] - p[j] / i; //p[j] * (1 - 1/i)
}
}
}
以下为 AC 代码 这个真的是个水题。。只要你懂欧拉函数是什么。。以后还要在学习一下
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
int euler(int n)
{
int tmp=n;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
tmp = tmp - tmp/i;//tmp = tmp * (1 - 1/i) 直接算的话会变成0出问题 变个形
while(n%i==0)
n/=i;
}
}
if(n>1)
tmp=tmp/n*(n-1);
return tmp;
}
int main()
{
int n;
while(cin>>n&&n)
{
cout<<euler(n)<<endl;
}
return 0;
}