zoukankan      html  css  js  c++  java
  • 夏令营讲课内容整理 Day 6 Part 2.

    Day 6的第二部分,数论
    数论是纯粹数学的分支之一,主要研究整数的性质
     
    1.一些符号:
    a mod b 代表a除以b得到的余数
    a|b a是b的约数
    floor(x) 代表x的下取整,即小于等于x的最大整数,也可以认为是直接舍去小数部分
    (这个应该是一个符号,但我不知道怎么打出来。。下面那个ceil也是)
    ceil(x) 代表x的上取整,即大于等于x的最小整数,也可以认为是直接舍去小数部分再+1.
    gcd(a,b) 表示a与b的最大公约数
    lcm(a,b) 表示a与b的最小公倍数
    累加符号∑ 累乘符号∏
    logab代表以a为底的b的对数,ln表示以e为底的对数,lg代表以10为底的对数
     
    2.质数
    也称素数,是质因子只有1和它本身的数。
    与质数相对的是合数,合数在因数拆分时可以拆分成至少两对其他数的乘积。
    特殊规定,1既不是质数也不是合数。
    可以证明,素数是无限多个的,证明从略。
     
    3.唯一分解定理
    算术基本定理之一。
    定理是这样描述的:对于每一个大于1的自然数都可以写成质数的积,而这些因子按照大小排列后,只有一种结果(写法只有一种)。
    我并不会证。。。我太弱了
    这个定理是分解质因数的基础。它告诉我们可以用质数乘积的形式处理一些大数字,处理一类和约数有关的问题。
    显然,一个数n最多有一个大于√n的质因子。
     
    4.筛法
    用来快速求一个数是不是质数的算法
    通常有两种筛法:埃氏筛和欧拉筛
     
    4.1埃氏筛法
    核心思想:从2到n枚举,当找到一个质数时,枚举它的所有倍数,这些倍数绝对不可能是质数。
    int cnt;
    int prime[maxn];
    bool vis[maxn];
    void Eratosthenes(int n){
        for (int i=2;i<=n;i++)
            if (!vis[i]){
                prime[++cnt] = i;
                for (int j = i*2;j<=n;j+=i)
                    vis[j] = 1;
            }
    }
     
    时间复杂度是O(nloglogn),证明从略。
     
    4.2欧拉筛法
    核心思想是通过让每一个数只会被它最小的质因子筛到,从而每个数只会被筛一次,时间复杂度O(n)。
    对于任意一个合数,我们可以拆成最小质因子*某数i的形式,我们枚举这个数i,然后再枚举出所有筛的质数。
    当我们枚举的质数可以整除i时,如果再往大里枚举,枚举的质数就不可能是最小质数了。这时就可以终止循环,继续枚举下一个i。
    int cnt;
    int prime[maxn];
    bool vis[maxn];
    void Eular(int n){
        for (int i=2;i<=n;i++){
            if (!vis[i])    
                prime[++cnt] = i;
            for (int j=1;j<=cnt && prime[j]*i<=n;++j){
                vis[prime[j]*i] = 1;
                if (i % prime[j] == 0)
                    break;
            }    
        }
    }
     
     
    5.取模
    我想您应该早已熟知余数的定义。
    a % b(就是a mod b)得到的结果是a除以b得到的余数。
    性质:a %b = a-(a/b)*b
    一些题目要求对答案取模,如果这个答案是负的,应该加上模数而不是除。
    取模的性质:
    (a±b) % p = ((a % p) ± b) % p
    (a*b) %p=(a % p) * (b % p)
     
    6.最大公约数
    辗转相除。
    int gcd(int a, int b){
      if (!b)
        return a;
      return gcd(b, a % b);
    }
     
     
     
    7.同余
    这里引入一个新符号,a≡b(mod n)表示a与b在模n意义下的余数相同,称为a与b同余。
    同余的性质:
    1.反身性 a≡a (mod m)
    2.对称性 若a≡b(mod m),则b≡a (mod m)
    3.传递性 若a≡b (mod m),b≡c (mod m),则a≡c (mod m)
    4.同余式相加 若a≡b (mod m),c≡d(mod m),则a+c≡b+d (mod m)(或换成-)
    5.同余式相乘 若a≡b (mod m),c≡d(mod m),则ac≡bd (mod m)
     
    7.1逆元
    如果 ax≡1(mod n),那么x为a关于模n意义下的逆元。
    逆元一般用inv简称。
    当gcd(a,n) = 1时x为一唯一值,否则不存在,证明从略。
    其实可以这么想,x为模n意义下的倒数,也就是1/a,我们可以类比实数意义下的倒数在模n意义下a乘以b的逆元,相当于模n意义下的a/b。
    求逆元的方法,接下来讲。
     
    8.扩展欧几里得算法
    (借鉴了gty哥哥课件的思路)
    简称扩欧,exgcd。
    用来求解形似ax+by = gcd(a,b)一类方程的解。
    这里的x和y不一定是正整数,有可能是负数或0.
    比如说我举个例子,求一直线ax+by+c = 0上有多少个整数点(x,y)满足x∈[x1,x2],y∈[y1,y2]
    边界情况:
    当b=0时,gcd(a,b)=a,x=1,y=0
    假设 ax1 + by1= gcd(a,b),bx2 + (a % b)y2= gcd(b,a % b)
    由gcd的意义,知gcd(a,b) = gcd(b,a % b),那么有ax1 + by1 = bx2+ (a % b)y2;
    也就是说ax1 + by1 = bx2 + (a - [a / b] * b)y2 = ay2 + bx2 - [a / b] * by2;
    也就是说ax1 + by1 == ay2+ b(x2 - [a / b] *y2);
    那么,x1 = y2; y1 = x2 - [a / b] * y2;
    这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2。我们可以通过不断递归调用求解。
    void exgcd(int a, int b, int &d, int &x, int &y){
      if (!b) {
        d = a;
        x = 1;
        y = 0;
      }
      else {
        exgcd(b, a % b, d, y, x);
        y -= (a / b) * x;
      }
    }
    我们这样只能得出一组解,其他解呢?如果我们现在有解(x1,y1),任取另外一组解(x2,y2),则有ax1 + by1 = ax2 + by2 = gcd(a, b),变形可以得到a(x1 – x2) = b(y2 – y1),两边同时除以gcd(a, b),得到a’(x1 – x2) = b’(y2 – y1),因为(a’,b’)=1,所以(x1-x2)一定是b’的倍数,取x1-x2=kb’,得y2-y1=ka’。
    所以我们有以下结论:
    对方程ax+by+c=0,一组整数解为(x0,y0),则它的任意整数解可以写成(x0+kb’,y0-ka’),其中a’=a/gcd(a, b),b’=b/gcd(a, b)
    关于ax+by=c有没有解,我们有这么一个结论:
    对于方程ax+by=c(a,b,c均为整数),如果c为gcd(a,b)的倍数,则方程有整数解,反之无整数解。因为a和b都是gcd(a,b)的倍数,所以ax+by一定也是gcd(a,b)的倍数,如果c不是gcd(a,b)的倍数,一定无解。
    那刚才那道题怎么做呢?
    方程变形为ax+by = -c,看一下-c是不是gcd(a,b)的倍数,然后用exgcd求一下ax+by = gcd(a,b)的解,记为(x0,y0)。
    等式两边同乘(-c)/gcd(a,b),就有ax0'+by0' = -c
    用刚才的结论,求出使x = x0 + kb'落在区间[x1,x2]内的k的范围和使y = y0-ka'落在区间[y1,y2]内的k的范围,取交集就是答案。
     
    9.费马小定理
    如果p是质数,并且gcd(a,p) = 1,那么 a^(p-1) ≡ 1 (mod p)
    由这个式子我们可以知道,a关于p的逆元就是a^(p-2) % p,用快速幂就好,证明从略。
     
    10.快速幂
    快速幂用了一个倍增的思想,我把它放在Part 3.
     
    11.排列组合
     
    11.1排列
    排列数指的是从n个数中任取m个元素排成有顺序的一列,这一列称为一个排列,所有排列总数称为排列数。
    生成排列数:DFS 或 next_permutation
    从n个元素里取m个成为排列记为A(n,m) (原谅打不出来)
    A(n,m) = n * (n-1) * (n-2) * (n-3) * ... * (n-m+1) = n!/(n-m)!
    11.2组合
    组合数指的是从n个数中任取m个 元素设为一组,叫做一个组合,这样所有的组合的数量就是组合数。
    可以发现,排列要求元素带有顺序,而组合则不考虑顺序。
    公式是C(n,m) = n * (n-1) * (n-2) * (n-3) * ... * (n-m+1)/m! = n!/m!(n-m)!
    组合的性质:
    C(n,m) = C(n-1,m-1) + C(n-1,m)
    C(n,m) = C(n,n-m)
    C(n,m) = C(n,m-1)*(n-m+1)/m (m>0)
    由性质3可递推某一n确定下的组合数
     
    其实排列组合这一块有很多内容,然而。。。
    我觉得我讲得再多也没高中数学选修2-3讲得明白。。。。
    所以,如果有没提到的地方,请参见高中数学选修2-3。。
     
     
     
     
     
     
     
  • 相关阅读:
    「Wallace 笔记」K-D tree 区域查询时间复杂度简易证明
    「LOJ #2980」「THUSCH 2017」大魔法师
    「Wallace 笔记」快速上手回文自动机(PAM)
    「ZJU Summer Training 2020
    「AtCoder AGC002F」Leftmost Ball
    文案高手的18项修炼
    高性能MySQL实战
    300分钟搞懂 Spring Cloud
    腾讯产品启示录
    300分钟吃透分布式缓存
  • 原文地址:https://www.cnblogs.com/OIerShawnZhou/p/7435756.html
Copyright © 2011-2022 走看看