【欧拉函数】一看到质数就头大,欧拉函数快速解决

366 阅读3分钟

最近在准备蓝桥杯经常会遇到质数问题,虽然说求量数是否互为质数这种问题已经考烂了,是基础不过的题型了,但是对于我这种概念经常搞不懂的人真的很为难。本文主要是对质数题型做一个总结。

判断x是否为质数

public static boolean isPrime(int num) {
    if (num < 2) {
        return false;
    }
    for (int i = 2; i <= Math.sqrt(num); i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}

判断一个数是否为质数的方法是,从2开始遍历到这个数的平方根。简单解释一下: 当判断一个数n是否为质数时,我们只需要判断它是否能被小于等于它的平方根的数整除即可。因为如果n能被一个大于它的平方根的数整除,那么这个数一定能被一个小于等于它的平方根的数整除

举个例子,假设我们要判断15是否为质数。它的平方根约为3.87,所以我们只需要判断它是否能被2、3、4、5整除即可。如果它能被这几个数中的任何一个整除,那么它就不是质数;如果它不能被这几个数中的任何一个整除,那么它就是质数。

因此,在判断一个数是否为质数时,我们只需要遍历小于等于它的平方根的数即可,这样可以减少遍历的次数,提高判断的效率。就不多说了,相信大家第一次接触C语言的时候,素数就是典型的例子了。 下面才是我们的重头戏。

判断区间质因子的个数

我们会遇到这么一个问题:给定正整数n,在小于等于n中,有几个与n互质的数? 朴树算法:我们会将遍历n遍,去判断i是否是n的素因子。在判断是否是素数的时候,有要进行m次遍历,显然这个时间复杂度为O(n^2)。 那么我们会引入一个欧拉函数,什么是欧拉函数?欧拉函数是干什么的?这名字听的好高端,不用怕,我们简单了解一下就欧克。

什么是欧拉函数

欧拉函数主要用于计算小于或等于一个正整数n的正整数中,与n互质的数的数目。 诶,这不就和我们的题目不谋而合了嘛。接下来用一张图简单的看一下欧拉函数的公式,

image.png 那么你可以尝试一下套用欧拉函数的公式计算一下当n = 8时,其区间内互质的个数是不是4啦。 那么欧拉公司如何转换成代码呢?

private static long eulerFunction(long a) {
        int res = a;
        for (int i = 2; i <= a/i; i++) {
                if (a % i == 0) {
                        res = res / i * (i-1);
                        while (a % i ==0) {
                                a /= i;
                        }
                }
        }
        if (a > 1) {
                res = res / a * (a-1);
        }
        return res;
}

练一练

题目:0互质数的个数 - 蓝桥云课 (lanqiao.cn)

解题代码:

import java.util.Scanner;

/**
 * 有多少个x 与 a^b 互为质数
 * 结果取模998244353 
 * 
 * 输入 a b 
 * @author colir
 *
 */
public class 互质数的个数 {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		long a = scanner.nextLong();
		long b = scanner.nextLong();
		scanner.close();
		long res = eulerFunction(a);
		res = (res*fastpow(a, b-1)) % 998244353;
		System.out.println(res);
	}
	// 计算互质的个数—— 欧拉函数
	private static long eulerFunction(long a) {
		long res = a;
		for (int i = 2; i <= a/i; i++) {
			if (a % i == 0) {
				res = res / i * (i-1);
				while (a % i ==0) {
					a /= i;
				}
			}
		}
		if (a > 1) {
			res = res / a * (a-1);
		}
		return res;
	}
	// 快速幂算法
	private static long fastpow(long a,long b) {
		long res = 1;
		while(b > 0) {
			if ((b & 1) > 0) {
				res = (res * a) % 998244353;
			}
			a = (a * a) % 998244353;
			b >>=  1;
		}
		return res;
	}
}

本题涉及到了快速幂算法,上一期我做过笔记了,就不多说了,大家可以看一下【快速幂算法】这篇文章