数学知识1

重点: 数学知识:

1.数论-试除法
:最简单的!

- 质数/素数

合数是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。与之相对的是质数,而1既不属于质数也不属于合数。最小的合数是4。

-在这里插入图片描述

质数/素数
定义:从2开始
只包含1和本身的这两个约数

质数的判定

两个条件:
<2 false
%=0
缺点:
约数成对存在的,变小时间。
开平方 - 慢
i*i<=n

简单化简-试除法

a|b--b除以a=整数,余数为0,b为被除数,a为除数
说明
d|n--n除以d=整数,余数为0.
(n/d)|n--n除以(n/d)=整数,余数为0.
例子:
n=8,d=4
d|n
48 = 2
(n/d)|n
(8/4)|8=4
这两个数是成对出现的,所以可以进行简化
这个可以替代循环里面的,节省时间

暴力版:
boolean is_prime(int x){
if}

boolean is_prime(int x){
	if(x<2)return false;
	for(int i=2;i<x/i;i++){
		if(x%i==0)return false;
	}

}
时间复杂度o跟下n

代码:

package 数学知识;

public class 质数的判定 {
    //暴力解法
    public static boolean is_prime1(int x){
        if(x<2) return false;
        for(int i=2;i<x;i++){
            if(x%i==0){
                return false;
            }
        }
        return true;
    }
    //稍微简化--证明法:合数:N,存在M,使得2<=M<=根下N
    public static boolean is_prime2(int x){
        if(x<2) return false;
        //根据 质数的乘积是成对出现的所以,
        //2<=M<根下N
        for(int i=2;i<=Math.sqrt(x);i++){
            if(x%i ==0)return false;
        }
        return true;
    }
    //更简化版
    public static boolean is_prime3(int x){
        if(x<2)return false;
        //M|N,N/M|N,所以直接省略一个除数和判断
        for(int i=1;i<=x/i;i++){
            if(x%i==0)return false;
        }
        return true;
    }

    public static void main(String[] args) {
        int x=8;
        if(is_prime3(x)) System.out.println("质数");
        else System.out.println("不是质数");
    }
}

- 分解质因数

分解质因数的时候还用到了一个没讲的结论:
任何数都可以表示成质数的乘积。

—分解质因数与质因数不一样,分解质因数是一个过程,而质因数是一个数。

原理:

根据算术基本定理,不考虑排列顺序的情况下,每个正整数都能够以唯一的方式表示成它的质因数的乘积。
n=p1^a1 * p2^a2 *p3^a3.....pn^an
比如一个数16 在分解时先找到2这个质因子,
然后由于16/2后还可以/2,
所以会在2这个质因子上产生次方 2^4=16
比如说12:
i=2;
12/2=66/2=3//2^2
3/3=1//3^1
所以12可以被分解为
2^2*3^1=12
不优化版本:从2~n 找到能整除的因子然后算次方

原理2:

n中最多只含有一个大于sqrt(n)的因子。
证明通过反证法:如果有两个大于sqrt(n)的因子,那么相乘会大于n,矛盾。证毕

于是我们发现最多只有一个大于sqrt(n)的因子,对其进行优化。

先考虑比sqrt(n)小的,代码和质数的判定类似
最后如果n还是>1,说明这就是大于sqrt(n)的唯一质因子,输出即可

找到这些数和幂
代码:

package 数学知识;

import java.util.Scanner;

/*前提知识:
1.从2开始找第一个质数,找到后使劲除
2.每个数只有一个大于它本身开平方的数*/
public class 分解质因数 {
    //暴力法
    public static void divide1(long x){
        for(int i=2;i<=x;i++){
            if(x % i==0){
                int s=0;
                while (x%i==0){//8%2=0//4%2==0//2%2=0//\
                    x = x/i;//8=4//4=2//2=1
                    s++;//s=1//s=2//s=3
                }
                System.out.println(i+" "+s);
            }
        }
        System.out.println();
    }
    public static void  divide2(long x){
        //首先质因数肯定是一个质数-因此更改边界
        for(int i=2;i<=x/i;i++){//从2开始往后做除法,第一个能被除开的数一定是原数n的一个质数
            if(x%i==0){//x中已经不包含2-x-1任何的质因子了,一直再除,x=x/i
                //i中已经不包含任何质因子了,i一开始已经是质数了
                int s =0;
                while (x%i==0){
                    x = x/i;
                    s++;
                }
                System.out.println(i+" "+s);
            }
        }
        if(x>1)System.out.println(x+" "+1);//x 的质因子最多只包含一个大于 根号x 的质数。如果有两个,这两个因子的乘积就会大于 x,矛盾
    }

    public static void main(String[] args) {
        //数字使用longlong,n使用整形
        Scanner sc = new Scanner(System.in);
        //int n = sc.nextInt();
        int n=2;

        long x = 6;
        divide2(x);


    }

}

筛质数:

  • 简单版暴力版

给定数n
1-n中有几个质数,先判断,算个数。

package 数学知识;

import java.util.Scanner;

public class 筛质数 {
    public static boolean is_prime(long x){
        if(x<2) return false;
        for(int i=2;i<=x/i;i++){
            if (x%i==0)return false;
        }
        return true;
    }
    //给定一个正整数 n,请你求出 1∼n 中质数的个数。
    public static void shai(long n){
        //1-n
        int s =0;
        for(long i=2;i<=n;i++){
            if(is_prime(i)){
                s++;
            }
        }
        System.out.println(s);
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n =8;
        shai(n);
    }
}

  • 朴素筛法
    不管出现哪个数,都进行给他加然后就可以消掉所有的,不过进行了很多重复性操作。
package 数学知识;

import java.util.Scanner;

public class 筛质数2 {
    static int N =100010;
    static boolean[] st = new boolean[N];
    static int[] primes = new int[N];
    static int n;

    public static void get_prime1(){
        int num=0;
        //素数和合数都筛
        for(int i=2;i<=n;i++){
            if(st[i] == false) primes[num++] =i;//注意这里没有大括号
            //就算来了一个4上面不执行下面也会执行
            for(int j=i;j<=n;j=j+i){//4,8,12
                st[j] =true;
            }
        }
        System.out.println(num);//num从0开始个数刚好是num++
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        get_prime1();
    }
}

  • 埃式筛法:

只筛质数-因为合数也是由质数得来的

1.每次一找到一个数判断st,false说明现在还没访问,-放进数组-再进行循环判断数组中有没有这个的倍数的数据

package 数学知识;

import java.util.Scanner;

public class 筛质数2 {
    static int N =100010;
    static boolean[] st = new boolean[N];
    static int[] primes = new int[N];
    static int n;
    public static void get_prime(){
        int num=0;
        for(int i=2;i<=n;i++){
            if(st[i]==false) primes[num++] = i;
            for(int j=i;j<=n;j=j+i){
                st[j] = true;
            }
        }
        System.out.println(num);
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        get_prime();
    }
}

在这里插入图片描述
线性筛法=n只会被最小质因数筛掉
·
代码:

package 数学知识;

import java.util.Scanner;

public class 筛质数线性筛法 {
    static int N =100010;
    static boolean[] st = new boolean[N];
    static int[] primes = new int[N];
    static int n;
    static int num;
    public static void get_primes(int n){
        for(int i=2;i<=n;i++){
            if(st[i]==false) primes[num++] = i;
            //每次用最小的去筛
            for(int j=0;primes[j]*i<=n;j++){//找到ihej
                st[primes[j]*i]=true;
                if(i%primes[j] == 0) break;
                //break 是为了后面减少重复筛选。
                //举个例子,对于一个数9,92=18将18标记为合数,循环继续;
                // 93=27将27标记为合数,此时发现9%3=0,循环退出。
                // 如果将循环继续下去会出现筛除95=45的情况,
                // 而45=153,在15时会被在筛去一次,故不可行
            }
        }
        System.out.println(num);
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        get_primes(n);
    }
}

在这里插入图片描述
线性筛法比较快。

约数

求所有约数

定义:
约数,又称因数。
整数a除以整数b(b≠0) 除得的商正好是整数而没有余数,我们就说a能被b整除,或b能整除a。
a称为b的倍数,b称为a的约数。
一个数的约数也是整对出现的。

试除法求所有约数
超级暴力法

package 数学知识;
//输入样例:
//2
//6
//8
//输出样例:
//1 2 3 6
//1 2 4 8

import java.util.Scanner;

public class 试除法求约数 {
    public static void yueshu(int n){
        for(int i=1;i<=n;i++){
            if(n%i==0){
                System.out.print(i+ " ");
            }
        }
    }
    public static void main(String[] args) {
        Scanner sc =new Scanner(System.in);
        int n= sc.nextInt();
        for(int i=0;i<n;i++){
            int x = sc.nextInt();
            yueshu(x);
            System.out.println();
        }


    }

}

第二种方法:
数组使用array.sort进行排序
因为数据是成对出现的因此查找的时候可以省略

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int N =1000;

    public static void yueshu(int n){
        int[] res = new int[1000];
        int num = 0;
        for(int i=1;i*i<=n;i++){
            if(n%i==0){
                res[num] = i;
                num++;
                if(i != n/i){
                    res[num] = n/i;
                    num++;
                }
            }
        }
        Arrays.sort(res,0,num);
        for(int i=0;i<num;i++){
            System.out.print(res[i] + " ");
        }
    }
    public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        while (n-->0){
            int x = sc.nextInt();
            yueshu(x);
            System.out.println();
        }
    }
}

第三种方法:
使用linklist进行存储。
因为是集合使用collection进行排序

package 数学知识;
//输入样例:
//2
//6
//8
//输出样例:
//1 2 3 6
//1 2 4 8

import java.util.*;


    public static void yueshu2(int n){
        ArrayList<Integer> res = new ArrayList<>();
        //因为约数也是成对出现的,除了完全平方数是一个 例如4 -2
        //所以只找一半就可以找到所有值。
        for(int i=1;i*i<=n;i++){
            if(n%i==0){
                //首先i肯定是约数一个,如果是成对出现的则
                res.add(i);
                if(n/i != i){
                    res.add(n/i);
                }
            }
        }
        //加完所有的数之后输出的时候按照顺序
        Collections.sort(res);
        for(int i:res){
            System.out.print(i+ " ");
        }
    }

    public static void main(String[] args) {
        Scanner sc =new Scanner(System.in);
        int n= sc.nextInt();
        for(int i=0;i<n;i++){
            int x = sc.nextInt();
            yueshu2(x);
            System.out.println();
        }
    }

}

在这里插入图片描述

求约数个数:

n/d==0 推出 d能整除n 记做 d|n ,d称为n的约数。
求约数个数用的算数基本定理
算数基本定理用到质因子分解
因此约数个数间接用到质因子分解

算数基本定理
在这里插入图片描述

代码

package 数学知识;

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

public class 试除法求约数个数2 {
    static int N=1000010;
    //乘法答案比较长 lonh
    static long res = 1;//cheng 1
    static HashMap<Integer,Integer> map = new HashMap<>();
    static int n;
    public static void yueshu_num(int n){
        //明白一个道理:算法原理由质因子分解而来,而计算约数个数,需要用到算法原理,则间接使用到质因子分解
        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);
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        while (n-->0){
            int x = sc.nextInt();
            yueshu_num(x);
        }
        //shuchu
        for(Map.Entry<Integer,Integer> map:map.entrySet()){
            res = (res * (map.getValue()+1))%N;
        }
        System.out.print(res);
    }
}

算数基本定理:

算术基本定理可表述为:
任何一个大于1的自然数 N,如果N不为质数,
那么N可以唯一分解成有限个质数的乘积N=P1^a1P2^a2P3^a3......Pn^an,
这里P1<P2<P3......<Pn均为质数,
其中指数ai是正整数。
这样的分解称为 N 的标准分解式。
最早证明是由欧几里得给出的,由陈述证明。
此定理可推广至更一般的交换代数和代数数论。

约数/因数
“约数也叫做因数,是因数的另一个称呼”
约数个数根据公式可以:
在这里插入图片描述

约数之和:

约数之和:用到的定理:也是和约数个数是一样的,


算法分析
基本思想:
如果 N=p1c1∗p2c2∗…∗pkckN=p1c1∗p2c2∗…∗pkck
约数个数:(c1+1)(c2+1)∗…∗(ck+1)(c1+1)(c2+1)∗…∗(ck+1)
约数之和: (p10+p11++p1c1)∗…∗(pk0+pk1++pkck)(p10+p11++p1c1)∗…∗(pk0+pk1++pkck)
while (b -- ) t = (t * a + 1) % mod;

t=t∗p+1t=t∗p+1
t=1t=1
t=p+1t=p+1
t=p2+p+1t=p2+p+1
……
t=pb+pb−1++1

因为公式就是
while (b -- ) t = (t * a + 1) % mod;
每次都可以扩展成这样

在这里插入图片描述
展开就可以解决,发现是所有的排列组合
代码:

注意事项:
边界值涉及到连乘的时候,就是有问题的时候,一版用long结构进行定义
package 数学知识;

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

//给定 n 个正整数 ai,请你输出这些数的乘积的约数之和,答案对 109+7 取模。
public class 约数之和 {
    static int mod = 1000000007;
    static long res = 1;//cheng 1
    static HashMap<Integer,Integer> map = new HashMap<>();
    static int n;
    public static void yueshu_num(int n){
        //明白一个道理:算法原理由质因子分解而来,而计算约数个数,需要用到算法原理,则间接使用到质因子分解
        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);
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        while (n-->0){
            int x = sc.nextInt();
            yueshu_num(x);
        }
        //map的方式进行简单公式遍环
        //t = (t*p+1)%mod
        for(Map.Entry<Integer,Integer> map :map.entrySet()){
            long t=1;//这个数很大
            int p = map.getKey();
            int n = map.getValue();
            while (n-->0){
             t = (t*p+1)%mod;
            }
            res = (res*t)%mod;
        }
        System.out.print(res);
    }

}

在这里插入图片描述

辗转相除法

为甚对?

//辗转相除法:
//d为a,b的公约数
//则 d 为(b,a%b)的公约数
//证明:
//a%b = a-(a/b)b=a-cb
//d|a,d|b--> d|a-kb--->d|b-(a%b)
//因为d|b-a%b,-->a|b-a%b+a%b-->d|b
//所以d为约数

在这里插入图片描述
gcd非常快速的。

import java.util.Scanner;

//辗转相除法:
//d为a,b的公约数
//则 d 为(b,a%b)的公约数
//证明:
//a%b = a-(a/b)b=a-cb
//d|a,d|b--> d|a-kb--->d|b-(a%b)
//因为d|b-a%b,-->a|b-a%b+a%b-->d|b
//所以d为约数
public class Main {
    public static int gcd(int a,int b){
        return b!=0 ?gcd(b,a%b):a;

    }
    public static int gcd2(int a,int b){
        if(b==0)return a;
        return gcd(b,a%b);
    }
    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();
            //gcd(a,b);
            System.out.println(gcd2(a,b));
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值