数学知识:欧拉函数

欧拉函数:

#include
using namespace std;
typedef long long ll;
int main()
{
    ll k;
    scanf("%lld",&k);
    while(k--)
    {
        ll x;
        scanf("%lld",&x);
        ll res=x;
        //如果i是x的约数,那么x/i也是x的约数,那么x就可以化成更小的了。如8的约数是2,4,8,那么当i=2时,就可以把8化成4了,在化×成2,这样就是2*2*2,。这样就不会算成2*4而是2*2*2
        //是因为做法要求的是尽量约数要小,指数要大,所以x的约数一定比x/i小,一旦比x/i大了,那说明该数没有约数了,就进行下面的if(x>1)语句
        //质因数从2开始
        for(ll i=2;i<=x/i;i++)
            if(x%i==0)
            {
                res=res/i*(i-1);
                //这个式子是转换过来的
                //原式为:res * (i - 1 )/i
                
//分解质因数要求必须是质数也是因数,但这里i可能取到合数比如4,不用担心,因为在while前面除以2的时候,除到不能再%2的时候才让i++到3的,所以连2都不能%了,2的倍数就自然不可能%
                while(x%i==0)x/=i;//把x除到x的最小质因数,方便后面if和这个for
                //例2:6
                //  i=2   3
                //  x=6 3 3 0,此时res=2为答案
                //x/i=3   1
                //res=3   2   
                
                //例3:8
                //  i=2 
                //  x=8 4 2 0
                //x/i=4
                //res=4      最后答案为4
            }
        if(x>1)res=res/x*(x-1);//如果x还大于1,说明还有一个质因子为x
        printf("%d\n",res);
    }
    return 0;
 } 

筛法求欧拉函数:

#include 
 
using namespace std;
 
typedef long long LL;
 
const int N = 1000010;
 
int primes[N], cnt;//primes存放已经找到的质数,cnt记录已经找到的质数数量
int phi[N];//存的欧拉函数(1~n中与n互质的数的个数)
bool st[N];//st标记某个数是不是质数
 
void get_eulers(int n)
{
    phi[1] = 1;//1的欧拉函数为1
    //遍历所有数字
    for (int i = 2; i <= n; i++)
    {
        if (!st[i])
        {
            primes[cnt++] = i;//如果i是质数,则质数+1,并把i存进来
            phi[i] = i - 1; //每个质数的欧拉函数都是1-i个,1~i-1都与它互质
        }
        //这个for是线性筛法
        for (int j = 0; primes[j] <= n / i; j++)//primes[j]<=n/i:变形一下得到:primes[j]*i<=n,把小于n的合数都筛了
        {
            st[primes[j] * i] = true;//i无论是质数还是合数,它的质数倍数都可以赋true
            //例:i=2时,找到i的最小质因子为2,所以2*2=4被赋true
            //    i=3时,找到i的最小质因子为3,所以3*3=9被赋true
            //    i=4时,前面已经找到4为合数所以不会让上面的if出错
            //像这样,不会让任何i和合数的情况下未被赋true,而导致上面的if出错
 
            //当primes[j]是i的最小质因子,说明primes[j]一定是i的倍数primes[j]*i的最小质因子
            //则说明对于i的倍数primes[j+k]*i的最小质因子也是primes[j],而非primes[j+k]
            //后面的任何i的倍数都不用看了,直接break,让i++找下一个数是否为质数
            if (i % primes[j] == 0)
            {
                //因为primes[j]是i的质因子,所以primes[j] * i的欧拉函数就是i的欧拉函数*primes[j]
                phi[primes[j] * i] = phi[i] * primes[j]; 
                break;
            }
                        
            //当i%primes[j]!=0时,说明此时遍历到的primes[j]不是i的质因子,所以primes[j]*i的最小质因子不是primes[j]
            //可以继续找primes[j+k]的i倍是否为最小质因子 
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
}
 
int main()
{
    int n;
    scanf("%d",&n);
 
    get_eulers(n);
 
    LL res = 0;
    for (int i = 1; i <= n; i++) res += phi[i];
    printf("%lld\n", res);
 
    return 0;
}

你可能感兴趣的:(算法基础,算法)