数学知识2

欧拉函数-求欧拉数

重要点:

1----N中与N互制的个数

1.先求质因数
质因数公式的边界:

 for(int i=2;i*i<=n;i++){

用质因数来使用公式进行求解

某个数N的欧拉函数是一个整数:表示与N互质的个数

1∼N 中与 N 互质的数的个数被称为欧拉函数,记为 ϕ(N)

若在算数基本定理中:
N=p1^a1*p2^a2*..Pk^ak,则:
--》这个是需要使用分解质因子进行求解

ϕ(N) =N*(1-1/p1)*(1-1/p2)...*(1-1/pk) 

在这里插入图片描述

证明:

在这里插入图片描述
1 2 3每个的欧拉函数
代码:
结构1-使用函数:

使用了map
1.map<Interger,Interger> map 
一个存储质因子,一个存储指数。
2.遍历的时候需要注意公式的应用,p为质因子
res = x;
res = res / p*(p-1);
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    //输入格式
    //第一行包含整数 n。
    //接下来 n 行,每行包含一个正整数 ai
    //输出格式
    //输出共 n 行,每行输出一个正整数 ai 的欧拉函数。
    static int N = 1000000007;

    public static Map euler(int n){
        HashMap<Integer,Integer> map = new HashMap<>();
        //分解质因子
        for(int i=2;i*i<=n;i++){
            while (n%i==0){
                n=n/i;
                map.put(i,map.getOrDefault(i,0)+1);
            }
        }
        if(n>1) map.put(n,map.getOrDefault(n,0)+1);
        return map;
    }


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        while (n-->0){
            int x = sc.nextInt();
            long res = x;
            Map<Integer,Integer> mp = euler(x);
            //输出使用公式进行
            for(Map.Entry<Integer,Integer> map:mp.entrySet()){
                int key = map.getKey();
                res =( res/key) *(key-1);
            }
            System.out.println(res);
        }
    }
}

代码2

package 数学知识;

import javax.swing.plaf.synth.SynthUI;
import java.util.Scanner;

public class 欧拉数3 {


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = 1;
        while (n-->0){
            int x = 8;
            long res = x;
            for(int i=2;i*i<=x;i++){
                if(x%i==0){
                    while (x%i==0){
                        x = x/i;
                    }
                    res = res/i*(i-1);
                }
            }
            if(x>1) res = res/x*(x-1);
            System.out.print(res);
        }
    }
}

线性筛-筛欧拉-欧拉数之和。

  • 简单方法:
package 数学知识;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

import static 数学知识.欧拉数.get_euler;

public class 欧拉数之和_多个 {

    public static Map get_euler(int n){
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i=2;i<=n;i++){//
            while (n%i==0){
                n = n/i;
                map.put(i,map.getOrDefault(i,0)+1);
            }
        }
        if(n>1)map.put(n,map.getOrDefault(n,0)+1);
        return map;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n= sc.nextInt();
        while (n-->0){
            int x = sc.nextInt();
            long ans = 0;
            for(int i=1;i<=x;i++){
                long res = i;
                Map<Integer,Integer> mapp= get_euler(i);
                for(Map.Entry<Integer,Integer> map:mapp.entrySet()){
                    int p  = map.getKey();
                    res = res/p*(p-1);
                }
                ans = ans +res;
            }
            System.out.println(ans);
        }
    }
}

  • 线性筛法进行求数
边界是i<=n
 for(int i=2;i<=n;i++){

不改动线性筛法,再进行求解

1.一个质素p的欧拉数
例如:
5:
1234
6
15
所以对于质数p欧拉数:p-11 2....p-1

问题:怎么使用线性筛的过程中进行呢。
 1.
  i%pj==0
说明pj是i的一个质因子,所以使用欧拉公式及性能累次求解时

线性筛法的公式:

for (int j = 0; primes[j] <= n / i; j ++)
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0)
            {
                break;
            }

如果加入了欧拉数的选择,在使用公式的时候需要的是

for (int j = 0; primes[j] <= n / i; j ++)
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0)
            {
               //说明prime[j]是i的质因子。所以使用欧拉函数和展开,并且primes[j]*i和i的质因子相同也就是phi相同。多承phi【i】
               phi[primes[j]*i] = phi[i]*primes[j];
            }

在这里插入图片描述
又因为欧拉公式使用的质因子,不会使用幂数,所以,i和i*p所使用的质因子是一样的
所以根据公式进行化简
只有系数不一样,所以
fai(pj,i) = pj fai(i)

 2.
  i%pj !=0:
premes[j]一定是i*primes[j]的最小质因子,并且primes[j] 不包含在i的质因子中。
所以
phi[i]中没有primes[j]这个数。
所以
phi[primes[j]*i] =:N= primes[j]*i 并且有primes[j]这个质因子
=primes[j]*i*(1-1/p1)*...*(1-1/pk)*(1-1/primes[j])
上面这个中间含有一个phi[i]
所以
phi[primes[j]*i] = primes[j]*phi[i]*(1-1/primes[j])=phi[i] * (premes[j]-1)
 for (int j = 0; primes[j] <= n / i; j ++)
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0)
            {
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
           //这个地方
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }

在这里插入图片描述

代码:
1.要看清楚是边界是i<=n

package 数学知识;

import java.awt.*;
import java.util.Scanner;



public class 线性筛欧拉数 {
    static int N = 100010;
    static boolean[] st=new boolean[N];
    static int[] primes = new int[N];
    static int[] phi = new int[N];
    public static long get_euler(int n){
        int num=0;
        phi[1] =1;
        //&&&这个地方是n
        for(int i=2;i<=n;i++){
            if(st[i] == false) {
                primes[num++] = i;
                //初始化
                phi[i] = i-1;//质数的欧拉数i-1
            }
            for(int j=0;i*primes[j]<=n;j++){
                st[primes[j]*i]=true;
                if(i%primes[j] == 0) {
                    phi[primes[j]*i] = primes[j]*phi[i];
                    break;
                }
               phi[primes[j]*i] = phi[i]*(primes[j]-1);
            }
        }
        long res =0;
        //欧拉数从1开始

        for(int i=1;i<=n;i++){
            System.out.println(phi[i]);
            res = res+phi[i];
        }
        return res;
    }
    public static void main(String[] args) {
        Scanner sc= new Scanner(System.in);
        int n = 6;
        long x = get_euler(n);
        System.out.println(x);
    }
}

快速幂运算

  • 暴力解法:

循环进行解决

package 数学知识;

import java.util.Scanner;

public class 快速幂运算 {
    //预处理快速幂,进行简化计算
    //给定 n 组 ai,bi,pi,对于每组数据,求出 abiimodpi 的值。
    static int mod = 1000000009;

    public static void quick_mi(int a,int b,int p){
        long ans =1;
        for(int i=1;i<=b;i++){
            ans = ans*a%p;
        }
        System.out.println(ans);
    }
    public static void main(String[] args) {
        Scanner sc= new Scanner(System.in);
        int n = sc.nextInt();
        while (n-->0){
            int a = sc.nextInt();
            int b = sc .nextInt();
            int p = sc.nextInt();
            quick_mi(a,b,p);
        }
    }
}

  • 二进制预处理解决

使用之前计算的数,可以进行缩短计算时间,避免重复计算。
在这里插入图片描述
在这

小技巧:
当把a删掉的同时,a也要随着进制的转换变换值,跟十进制类似。
110
从右边开始,进行第一位是2^0=1
第二位是2^1=2
第三位...

在这里插入图片描述
代码:
注意事项:

1.涉及到乘积类的算法,一般使用的都是long性的数据结构
2.模数据的时候,一定要看清楚
3.b右移一位时,也就是b=b/2
4.b判断当前位是不是1时,也就是判断b%==1
import java.util.Scanner;

public class Main {
    //给定 n 组 ai,bi,pi,对于每组数据,求出 abiimodpi 的值。

    public static long  quick_mi_er(long a,long b,long p){
        long res =1;
        //进行循环
        while (b!=0){
            if(((b&1)==1))res =  res*a%p;//如果有1,这一位
            //上面如果有一再执行,但是这个不是
            //右姨一位
            b = b>>1;
            //更新进制值,一旦右移,代表的值就会变大
            a = a*a%p;
        }
        return res;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        while (n-->0){
            long a = sc.nextLong();
            long b = sc.nextLong();
            long p = sc.nextLong();
            long res =quick_mi_er(a,b,p);
            System.out.println(res%p);
        }
    }
}

快速幂求逆元

注意点:

1.求逆元的时候,需要进行判断
 a模 p的乘法逆元存在
 要求:a和p互质。且p为质数。
 则由费马定理,p_1 = a^p-2 mod p;
package 数学知识;

import java.util.Scanner;

public class 快速幂求逆元 {
    //1.费马定理。a^p-1 mod p==1  条件:a与p互质,且p为质数
    //使用这个进行    求解
    //给定 n 组 ai,pi,其中 pi 是质数,求 ai 模 pi 的乘法逆元,若逆元不存在则输出 impossible。
    //注意:请返回在 0∼p−1 之间的逆元。
    public static long quick_ni(long a,long p_2,long p){//
        // 快速幂
        long res = 1;
        while (p_2!=0){
            if((p_2&1)==1) res = res*a%p;
            //右移一位
            p_2 = p_2>>1;
            //变值
            a = a*a%p;
        }
        return res;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        while (n-->0){
            long a = sc.nextLong();
            long p = sc.nextLong();
            if(a%p != 0){
                System.out.println(quick_ni(a,p-2,p));
            }else {
                System.out.println("impossible");
            }
        }
    }
}

扩展欧几里得算法

1.从欧几里得开始的。
多了两个系数。

求系数运算
x,y
ax+by=d
求x,y
在这里插入图片描述

在这里插入图片描述
代码

注意:
1.没有地址引用,在static里面定义系数
2.更新操作公式时,进行的使用是-x,y不要搞混。

    int d = exgcd(b,a % b, y,x);
    y -= a / b * x; //更新y,x不用变
    return d;
import java.util.Scanner;

public class Main {
    //因为没有变量引用,所以将变量定义在satic里面,则会简单一点
    static long x;
    static long y;
    public static long exd_gcd(long a,long b){
        if(b==0) {
            x = 1;
            y = 0;
            return a;//这个是因为gcd本来就是一个式子,然后这个是出口,同样的在使用递归时,也不能忘记这个递归的出口。
        }
        //重复性操作
        long d = exd_gcd(b,a%b);//同样的这个也是gcd使用的本来的样子,通过这样的方式,使用
        long tmp = x;
        x = y;
        y = tmp-a/b*y;
        return d;//最终计算祝来。
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        while (n-->0){
            long a = sc.nextLong();
            long b = sc.nextLong();
            exd_gcd(a,b);
            System.out.println(x+" "+y);
        }
    }
}

线性同余方程

解题思路:利用拓展欧几里得算法求解
将求解ai∗xi≡bi(modmi)ai∗xi≡bi(modmi)问题转换为拓展欧几里得问题,ai∗xi≡bi(modmi)⇒ai∗xi+m∗y≡bi(modmi)ai∗xi≡bi(modmi)⇒ai∗xi+m∗y≡bi(modmi).解的分析
当bi为(ai,m)的倍数时,方程有解,
因为ai∗xi为(ai,m)的倍数,m∗y也为(ai,m)的倍数,
若方程有解时,bi也必然为(ai,m)的倍数,
若方程无解,那么bi必然不是(ai,m)的倍数
拓展欧几里得算法是求解ai∗xi+m∗y≡(a,m)问题的,
若有解时,和ai∗xi≡bi相差的只是一个倍数bi/(ai,m),最后x乘上bi/(ai,m)就是最后答案。

也就是相差的
ax = b
a
x + y= gcd(a,m)
右边是变成bi

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值