数论

质数的定义:对于大于1的自然数,如果它的因子中只有1和它本身,则是一个质数也称素数。从定义可以看出质数的取值范围是从2开始的,小于2的数肯定不是质数。
质数的判定: 试除法
    假设 d是n的一个因子,那么n/d 也是n的一个因子。因此我们只需要枚举小的因子,如果小的因子都除不尽,则是一个质数, d <= n/d 即 d <= 根号下n  时间复杂度 O(根号下n)


    if (n < 2) return false;
    for (int i = 2; i <= n/i; ++i){  // 注意这里的 i <=  n/i 不要写成 i <= sqrt(n) 因为sqrt()函数比较慢 
        if (n % i == 0)
            return false;
    }
        return true; 
分解质因数:试除法
每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来 k = p1^a1 * p2^a2 * p3^a3 ...其中p1,p2,p3都是质因子(质数),叫做分解质因数。
如30=2×3×5 。分解质因数只针对合数,因为质数分解只能分解成1*n,而1又不是质数。
注意: n 中最多只包含一个大于根号下n的质因子,很明显如果有两个或者更多,那质因子相乘就大于n了。

void fun(int n){
    for (int i = 2; i <= n/i; ++i){  // 一个数的大于根号下n的质因数最多只有一个,为了找出那一个甚至可能还不存在的质因子而循环n - 根号下n 次太浪费了。
        int s = 0;
            while(n % i == 0){ // 因为质数分解是将一个合数分解成质数,而连除一个质数的时候并不会影响别的质数,只会影响和该质数有关的合数。比如i == 2 且 n % i == 0 那就在n的因子中去除了2即2的幂次。 
                n /= i;
                s += 1;  // s是质因子出现的次数,也即是质因子的指数
            }
        if (s)
        cout<<i<<" "<<s<<endl;  // 质因子i 的幂次是 s
    }
    if (n > 1) cout<<n<<" "<<1<<endl;  // 如果最后n == 1 说明所有的质因子在[2,根号下n]都找到了,当n > 1 时说明n此时就是大于根号n的质因子
    puts("");
}

质数筛法: 给定一个数字n,求出从1到n中有多少个质数
    埃氏筛法: 从头开始将所有质数以及它的倍数都给抹去,最后剩余的全都是质数

int fun(int n){
    int st[n+1] = {0};  // 记录从2到n中的数有没有被抹去
    int s = 0;
    for (int i = 2; i <= sqrt(n + 0.5); ++i){
        if (!st[i]){  
            s++;
            int j = i * i;
            while(j <= n){
                st[j] = true;  // 将i的倍数全不抹去
                j += i;
            }
        }
    }
    return s;  // s就是质素的个数
}
一个数的约数的求取: 试除法

vector<int> fun(int n){
    vector<int> nums;
    for (int i = 1; i <= n/i; ++i){  // 只需要枚举小的那一半约数就可以了
        if (n % i == 0){
            nums.push_back(i);
            if (i != n/i) nums.push_back(n/i);  // 如果 i == nums / i 的话 就只需要记录一个
        }
    }
    sort(nums.begin(),nums.end());
    return nums;
}
     
两数的最大公约数: 欧几里得算法

int gcd(int a,int b){
    return b ? (b,a % b) : a;
}

return b ? gcd(b,a % b) : a;  
    当b == 0 的时候就是求 (a,0)的最大公约数,因为0能够整除所有得约数(约数中不含0),所有(a,0)的最大公约数为a.
    当b == 0 的时候说明上一层的a % b == 0 也就是a == b,那么a,b都是最大公约数,而上一层的b传参数是当前层的a.
    当b != 0的时候,gcd(a,b) 就是 gcd(b,a % b)  gcd(a,b) 和 gcd(b,a % b) 的约数集合是相同的

如果c为a的约数同时也是b的约数的话,那么c就是ax + by 的约数,而 a % b 就是 a - by 因此c也是 a % b的约数

但是反过来: c是ax + by 的约数,而 a % c 不一定为0,b % c也不一定为0。 例如(4 - 1) % 3

组合数的常用公式:

 

质数与质数彼此之间是互质的,互质的两个数有一个性质: 如果一个数既能被p1整除,又能被p2整除,p1和p2又是互质的,那么这两个数的最小公倍数为: p1*p2
判断 ax + by = m 给定a > 0 和 b > 0 和 m 试判断 是否存在 正整数 x 和 y 使得 ax + by = m 成立  

当 m % a = r 且 r % b = 0 时就说明 存在正整数 x = m / a , y = r / b 使得 ax + by = m 成立

ax + by = m 可以看成 ax + r(余数) = m , 也可以看成 r(余数) + by = m  这就证明了上面的一行。


也可以用dfs()暴力深搜,暴力打表前几项,依此来观察规律。 
dfs(m,a,b){
    if (!m) return true;
    if (m){
        if (m >= a && dfs(m - a,a,b)) return true;
        if (m >= b && dfs(m - b,a,b)) return true;
    }
    return false;
}
求x的所有因子

for (int i = 1; i * i <= x; ++i)   // i的取值范围是 [0,sqrt(x)],也就说明如果i * j == x 且i != j 则一定有一个大于sqrt(x),一定有一个小于sqrt(x)。

// 因此我们要获得某个数字的所有因子,就只需要枚举i(0 < i < sqrt(x))就行了,如果i != sqrt(x)的话,那么另外的一个因子就是 x / i

  if (x % i == 0) {  // 说明i是x的一个因子
    ans[++cnt] = i;   
    if (i * i != x) ans[++cnt] = x / i;  // 判断i是不是sqrt(x)
  }
最小公倍数:
    A,B的最小公倍数 = A * B / gcd(A,B)
以下素数默认为正的素数:
-1.两个整数互质:两个整数的公约数只有1
-2.如果a与b互素,a与c互素,充要于 a与bc互素 
-3.p是素数,n是整数,如果p不能整数n的话,充要于 p和n互素(p不能整除n: n % p != 0,p本来的因子只有1和它 本身,n % p != 0 因此n和p的唯一的一个公共因子就是1,因此p和n互质)
-4.费马小定理: 如果p是质数,n是整数,一定有 p|(n^p - n) -> (n ^ p - n) % p == 0 -> (n^p) % p == n % p 
 -(1) 如果n是p的倍数,则 n^p % p == 0 
 -(2) 如果n不是p的倍数,则n^p % p = n % p -> n^(p - 1) % p = 1 % p -> n^(p - 1) 与 1 对p同余,则 (n^(p - 1)-1)% p == 0,n的逆元为 n^(p - 2)
-5.同余:给定一个正整数m,如果两个整数a和b满足a-b能够被m整除,即(a-b) % m == 0,那么就称整数a与b对模m同余,记作a≡b(mod m).
 -数学上,两个整数除以同一个整数,若得相同余数,则二整数同余,但是反过来不恒成立,如 -3 和 7就是关于10同余的两整数.
-6. 同余的性质:
    -1. a mod m == b mod m,c mod m == d mod m 则有(a + c) mod m == (b + d) mod m,(a - c) mod m == (b - d) mod m
    -2. a mod m == b mod m,c mod m == d mod m 则有(a*c) mod m == (b*d) mod m
    -3. 根据性质2就可推出: a mod m == b mod m 则有 a^n mod m == b^n mod m 以及 x*a mod m == x*b mod m (x是一个常数)
    -4. 同余无除法性质

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值