zoukankan      html  css  js  c++  java
  • 【数论总结】-----励志写好一篇数论总结↖(^ω^)↗//正在施工...未完工

      近期学了学数论,来写一波总结吧。

      (1)排列组合,比较基础的东西了吧。//只写个概念吧,(逃:

      概念:就是从n个不同元素中,任取m(m≤n)个元素并成一组,叫做从n个不同元素中取出m个元素的一个组合;从m个不同元素中取出n(n≤m)个元素的所有组合的个数,叫做从m个不同元素中取出n个元素的组合数。//这应该都知道吧

      公式://博客园现在这个图片功能,额.......

      组合恒等式:

       //不知道在博客园怎么弄公式,只好弄成图片上来了

      补充:1.Catalan数列,数列前几项为1,2,5,14,52,132,429......,通项公式://写个博客发现学会用word文档写公式了

    通过Catalan数列我们可以解决①从平面内(1,1)走到(n,n)且不能经过y =x上方的点的路径数②计算有多少种长度为n的括号序列(合法)③每次可以将一个元素入栈或者栈顶元素出栈的方案数④不同节点的二叉树计数⑤有 2n 个人,他们身高互不相同,他们要成两排,每一排有 n 个人,并且满足每一排必须是从矮到高,且后一排的人要比前一排对应的人要高的方案数

         2.挡板法:这个方法也是在组合数学中别叫经典的方法吧。几种常见的情况如下:

        ①如果有10个糖(n),一共有6个人(m),每个人必须都有一个。对于这种问题问你有多少种方法分糖那么这个就是

    //解释:因为我们要将10个糖分给6个人,所以我们就是要将10个糖分为6份,而且每人至少一个。然后我们要将10个糖分成6份就需要5个挡板,然后我们将这10个糖放成一排,因为10个糖完全相同,所以怎么排都是一样的//也就是说只有一种排法。然后这10个糖会出现9个空档,然后我们就要在这9个空挡中放5个挡板了,又因为这5个挡板无差异,所以怎么放都是无顺序的。所以就有这么多情况喽,就是上面说的。//图片放上来就这么大了,我也很无奈......

        ②但是如果允许有人可以拿不到糖这种情况怎么办呢??遇到这种情况时,我们可以先当成从每个盒子中拿出一个糖,这样我们现在就有n+m个糖了,然后在用①中的方法即可。这是为什么呢?因为我们先从每个盒子里面拿出一个糖,这样我们放的时候如果盒子里面只有一个糖,因为我们先从盒子里面借了一个糖,所以此盒子中是没有糖的。这样就可以处理好允许有空盒子的情况了//这应该很容易懂的吧。

        ③如果我们需要在每个盒子中至少再放入其编号个糖的话//其实放几个都无所谓,但为了好理解,所以就放入其编号个吧。(上面还是分糖,下面就往盒子里放糖了,没人看见吧(逃:),出现这种情况的话怎么办呢??//相信你已经有思路了吧。我们就和②一样,②是让有的盒子是空的。而现在我们就先往盒子里放入其编号-1个糖//因为挡板法是至少放一个糖,这我们不是又可以用①中的公式来求了吗。没错,就是这么简单↖(^ω^)↗。

        3.鸽巢原理(抽屉原理)概说一下是什么吧:如果n+1个物体放进n个盒子,那么至少有一个盒子里包含两个或者更多的物体。//就这么多....鸽巢原理重要的就是这样思想。相信大家在高中之前就已经接触过这种思想了吧,我也就不多说什么了。

    //在网上看到的一则鸽巢原理的故事:已知n+ 1个正整数,它们全都小于或等于2n,证明当中一定有两个数是互质的。匈牙利大数学家厄杜斯(PaulErdous,1913 - 1996) 向当年年仅11岁的波萨 (LouisPósa) 提出这个问题,而小波萨思考了不足半分钟便能给出正确的答案。波萨是这样考虑问题:取n个盒子,在第一个盒子我们放1和2,在第二个盒子我们放3和4,第三个盒子是放5和6,依此类推直到第n个盒子放2n-1和2n这两个数。如果我们在n个盒子里随意抽出n+1个数。我们马上看到一定有一个盒子是被抽空的。因此在这n+1个数中必有两个数是连续数,很明显的连续数是互质的。因此这问题就解决了!这就是利用了鸽巢原理的核心思想。

         4.容斥原理:这个东西还是比较重要的吧。

        ①两个集合的容斥原理:如果要计数的事物有A,B两种,那么,先把A,B两个集合中的元素想加,发现在A和B中。A,B相交的这种情况被多算了,所以我们要减去。就像让我们求两个重叠矩形的面积一样。公式:A∪B=A+B-A∩B。

        ②三个集合的容斥原理:我们还是将这三个元素集合A,B,C的元素个数相加,然后我们可以容易的发现两两重合的部分被多加一次,三个重复的部分被多算了两次。就如下图:

    灰色部分为两两重合的部分,最中间的深灰色为三个集合重复的地方
      
        

        因此:我们可以很容易的看出来A∪B∪C=A+B+C-(A∩B-A∩B∩C)-(B∩C-A∩B∩C)-(C∩A-A∩B∩C)-2(A∩B∩C)

                           =A+B+C-A∩B-B∩C-C∩A+A∩B∩C

        所以公式就是:A∪B∪C=A+B+C-A∩B-B∩C-C∩A+A∩B∩C。//即为:三个圆内的-重合两次的-重合三次的。

        然后我们就可以发现容斥原理就是要计算几个集合合并的大小,我们要先将所有单个集合的大小计算出来,然后减去所有两个集合相交的部分,再加回三个集合相交的部分,再减去所有四个集合相交的部分,以此类推。

        所以我们就可以得出容斥原理的性质:集合S不具有性质的物体个数公共如下

    //总说就是A的个数如果是计数则加如果是偶数就是减了。

      例题:[HAOI2012]容易题,POJ3904水晶密码,8的倍数。

    ---------------------------------------------------补充的东西先就这么多了吧-----------------------------------------------

      接下来我们说说组合数的计算吧。

      ①加法递推-----O(n²)

      就是上面组合数恒等式的第二条

    1 int C[1001][1001]//根据实际情况开数组
    2 memset(C,0,sizeof(C))
    3 for(int i=0;i<=n;i++)
    4 {
    5     C[i][0]=1;
    6     for(int j=0;j<=i;j++)
    7         C[i][j]=C[i-1][j-1]+C[i-1][j];
    8 }

      ②乘法递推-----O(n)

    1 C[0]=1;
    2 for(int i=1;i<=n;i++)//K为摸数,n为第n行
    3 {    
    4     C[i]=(C[i-1]*(n-i+1)/i)%K;
    5     C[i]%=K;
    6 }

       组合数也差不多就这么多东西了吧,还有什么的话以后再补充好了。

      (2)最大公约数(gcd),最小公倍数(lcm)

      哇小学都学过的东西了吧,直接放定理也没有什么不妥是吧。//求最大公约数只需要用欧几里得算法(辗转相除法)

      定理:gcd(a,b)=gcd(b,a%b)(a>b且a%b!=0)

      补充:gcd(a,b)=gcd(b,a%b)(a>b且a%b!=0)证明

      我们先设D=a%b ∴a=k*b+D (k∈N)  ∴ D=a-k*b  上面很显然对吧。所以我们再设r=gcd(a,b); 所以我们可以很显然的得到下面的几个结论r|a, r|b(这里r|a表示r可以被a整除)∴显然得r|a-k*b//因为a和b都可以整除r。∴r|D成立 ∴r|a%b也成立 所以呢我们可以发现r=gcd(b,a%b);所以gcd(a,b)=gcd(b,a%b);

    1 int gcd(int a,int b)
    2 {return b==0?a:gcd(b,a%b);}

      当然最小公倍数与最大公约数的关系就是:lcm(a,b)=(a*b)/gcd(a,b)

      既然有欧几里得算法那当然也有扩展欧几里得算法了。

      (3)扩展欧几里得

       因为我们很显然的知道gcd(a,b)表示的是a和b的最大公因数,所以我们可以等到这样一个方程:gcd(a,b)=ax+by;我们也当然可以找到一组解x1,y1。可是我们怎么求呢?这时候就要用到扩展欧几里得了。

      设a>b,所以①当b=0时,gcd(a,b)=a,所以显然可以得到x1=1,y1=0;

     ②当a>b>0时,因为gcd(a,b)=gcd(b,a%b),所以我们也很明显的可以讲方程转换为:bx2+(a%b)y2=gcd(b,a%b);所以我们又可以得到bx2+(a%b)y2=ax1+by1;我们得到这个方程是干什么的呢?肯定是有用的哇(这不是废话吗....)。然后我们又可以将这个方程化为ax1+by1=bx2+(a-[a/b]*b)y2;//这里的[]表示向下取整,就是[4.9]=4这个意思。所以ax1+by1=bx2+ay2-[a/b]*by2;然后我们就可以得到ax1+by1=ay2+b(x2-[a/b]*b);这样结果不是很明了了,x1=y2,y1=(x2-[a/b]*b)。我们可以看出x1和y1的值是基于y2和x2的,我们只需要递归求解就好了,因为在递归的时候一定会有一个b=0情况的解,所以递归可以结束了。

        总的来说,扩展欧几里得就是用来求已知a,b,求x,y的一组解来满足ax+by=gcd(a,b);//解一定存在。具体就看下面代码吧

     1 void exgcd(int a,int b,int &x,int &y)
     2 {
     3     if(b==0)
     4     {
     5         x=1;
     6         y=0;
     7         return;
     8     }
     9     exgcd(b,a%b,x,y);
    10     int t=x;
    11     x=y;
    12     y=t-a/b*y;
    13 }

    例题:bzoj 1477[青蛙的约会],NOI2002[荒岛野人]

      补充:扩展欧几里得也差不多就是这了,我们在这里补充一下分解质因数好不好哇。

      (4)质因数

      质因数这一个东西在数论中也占据着十分重要的地位,那么我们就来谈谈质因数。

      分解质因数这个东西我们也就不必多说了吧,我们直接筛法求一下素数然后枚举就好了。

      下面我们给出一些结论吧:

      ①//其中p1,p2....pk是n的质因数,也就是说每一个数都可以由这种形式表达出来

      然后由①我们又可以得出n的所有因数的个数为(a1+1)(a2+1)...(ak+1).

      然后我们还可以得出n的正约束和为:  

      这也都是些结论吧。

      然后我们看一下这个例题:求m!分解质因数后因子n的个数。这怎么搞呢?如果我们直接相乘的话会超过数据类型的范围的。那么,我们再看看,m!=1*2*3*....*(m-2)*(m-1)*m。这个谁都知道吧...因为我们要求m!分解质因数后因子n的个数,所以我们可以把m!的阶乘化为和n有关的。但这怎么联系上呢?我们想,如果m!里含有因子n,那么m!的阶乘就一定可以表示成m!=(n*2n*3n*...*kn)*other//other表示不含因子n的数的乘积,这应该很容易懂的吧。然后我们又可以把这个式子化为:n^k*(1*2*3...*k)*other=n^k*k!*other。//这也很容易懂吧。又因为kn<=m,所以k的最大值就为m/n。我们从上面的表达式中还可以提取出k个n,我们每次循环除就好了,时间复杂度很可观。

      具体代码如下:

    1 while(m)
    2 {    
    3     sum+=m/n;
    4     m=m/n;
    5 }

      是不是在疑惑代码为什么如此之短,没错就是这么短。//好好理解下。

      (5)欧拉函数

      //欧拉函数在数论中也是很常用的一个部分.....

      (1)定义:欧拉函数是小于或等于n的数中与n互质的数的数目,用φ(n)表示欧拉函数的值。

          计算方法为:φ(x)=x(1-1/p1)*(1-1/p2)*(1-1/p3)*...(1-1/pn)

      (2)证明:

       ①:当n=p^k时(p为质数):

        因为对于一个素数p,φ(p)=p-1,又因为n=p^k。所以φ(n)=p^k-p^(k-1),因为除了p的倍数以外,其它的数全和n互质//解释因为小于p^k的正整数个数为p^k-1个,其中和p^k不互质的正整数有{p*1,p*2,p*3....p*(p^(k-1)-1)}一共p^(k-1)-1个,所以φ(n)=p^k-p^(k-1)。

         ②:p*q的欧拉函数

        我们假设两个数p,q互质,以为欧拉函数是积性函数,所以φ(p*q)=φ(p)*φ(q);//记住是积性函数就好了......

       ③:对于任意正整数的欧拉函数

        因为我们知道,任意一个正整数n都可以表示为其素因子的乘积//前面质因数分解哪里提过。

                //直接搬过来

        所以很显然我们可以根据上面两条得出

             //pi就是n的素音字累乘上面的n为一共有多少个素因子

       ④欧拉函数的递推性质,根据这个我们可以在O(n)的时间内求出欧拉函数

        若(n%x==0&&(n/x)%x==0)则有φ(n)=φ(n/x)*x;
        若(n%x==0&&(n/x)%x!=0)则有φ(n)=φ(n/x)*(x-1)。

        代码如下:

     1 void Euler(int x)
     2 {
     3     memset(check,0,sizeof(check));
     4     int l=0;
     5     for(int i=2;i<=x;i++)
     6     {
     7         if(!check[i])
     8         {
     9             prime[++l]=i;
    10             phi[i]=i-1;
    11         }
    12         for(int j=1;j<=l&&prime[j]*i<=x;j++)
    13         {
    14             check[i*prime[j]]=1;
    15             if(i%prime[j])
    16                 phi[i*prime[j]]=phi[i]*(prime[j]-1);
    17             else
    18             {
    19                 phi[i*prime[j]]=phi[i]*prime[j];
    20                 break;
    21             }
    22         }
    23     }
    24 }

      

    //前两天考试,没有往下写,未完待续...

      

       

  • 相关阅读:
    精准测试
    git 管理
    git
    代码覆盖率测试
    vue 前端视频
    jenkins
    go学习资料
    4-4 求自定类型元素的平均
    4-3 简单求和
    4-2 多项式求值
  • 原文地址:https://www.cnblogs.com/lcyhaha/p/7719294.html
Copyright © 2011-2022 走看看