• 数学


    快速幂

      计算a^b   O(logb)

      先求x=a^(b/2) ,再求a^b=x*x;

      luoguP1226快速幂+取余

    long long qpow(long long a,long long b,long long p)
    {
        long long s=1;
        while(b>0)
        {
            if(b%2) s=s*a%p;
            a=a*a%p;
            b/=2;
        }
        return s;
    }
    

    逆元

      3/7=3*1/7  所以1/7就是7的乘法逆元

      mod意义下不能做除法,所以用乘法来代替,

      3/7(mod 11)=3*8(mod 11)

      1/7*7=1,7*8mod11=1;

      P3811 乘法逆元,线性递推

    费马小求逆元

      (给定p)若p为质,且p不是a的约数,

      根据费马小:a^(p-1)=1(mod p),所以a的逆元x=a^(p-2)

    欧拉定理求逆元

      若a,p互质,根据欧拉:aΦ(p)=1(mod p),所以a的逆元是aΦ(p)-1

      Φ(p)是?:  对于整数p,Φ(p)表示小于等于p的与p互质的数的个数

    GCD

      更相减损术:gcd(a,b)=gcd(a-b,b);

      辗转相除法,相当于优化过的更相减损术;

    辗转相除

      gcd(x,y)=gcd(x%y,y), O(log),why?:x%y<=x/2;

      当y<=x/2时,x%y<y<=x/2;

      当x/2<y<x时,x%y=x-y<x-x/2=x/2;

    最小公倍数

      lcm(a,b)=a*b/gcd(a,b);

    扩展GCD

      利用gcd思想可以求一组不定方程的解,给定a,b,求ax+by=gcd(a,b)的解;

      

      其中符号a/b为下取整;

      通过上面的方法只能求出无数个解其中的一个,

      通解为:

    无解的情况???

      ax+by=c,这个方程什么时候时无解?

      c不是gcd(a,b)的倍数时;

    推广到一般

      以上知道如何求ax+by=gcd(a,b)后,那么如何求ax+by=c(保证有解)呢?

      我们令k=c/gcd,那就相当于求k(ax+by)=gcd(a,b)*k,

      那么就求出ax+by=gcd(a,b)的解,再将解*k即可;

    同余

      什么是同余?a≡b(mod m) → a mod m=b mod m???

      不对,上面的式子没有考虑负数的情况;

      正确的解释为:a≡b(mod m) → (a-b) mod m=0;

    EG:

      求关于x的同余方程ax≡1(mod b)的最小正整数解,2<=a,b<=2*10^9;

      将原式转化为exgcd形式,相当于求ax-by=1;

      若a,b不互质肯定无解,用exgcd求出一组解,再求最小正整数解,

      只是某一组解就能求最小?  

      根据x加上b/gcd(a,b),同时y减去a/gcd(a,b)后,仍满足ax+by=c

      我们就可以求出最小的整数解;
      P1082同余方程
    /*
    ax≡1( mod b)等价于ax+by=1。
    那么题目就转化成求这个表达式x的最小值。
    可以把1看成gcd(a,b),于是就变成求解exgcd了。
    */
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    int a,b,x,y;
    
    int exgcd(int a,int &x,int b,int &y)
    {
    	if(b==0)
    	{
    		x=1;
    		y=0;
    		return a;
    	}
    	int s=exgcd(b,x,a%b,y);
    	int k=x;
    	x=y;
    	y=k-a/b*y;
    	return s;
    }
    
    int main()
    {
    	scanf("%d%d",&a,&b);
    	exgcd(a,x,b,y);
    	printf("%d",(x+b)%b);
    	return 0;
    }
    同余方程组
      %……¥&*……&……%,参见课件;
    离散对数
      %……¥&*……&……%,参见课件;
    线性筛法求质数※
      求[1,n]中所有的质数,n<=10^5? n<=10^7? 
      P3383线性求质数模板※ 
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    int n,m,num,x;
    int pri[10000002];
    bool b[10000002];
    
    bool judge(int n)
    {
    	for(int i=2;i<=n;++i)
    	{
    		if(!b[i]) pri[++num]=i;
    		for(int j=1;j<=num;++j)
    		{
    			if(i*pri[j]>n) break;
    			b[i*pri[j]]=1;
    			if(i%pri[j]==0) break;
                    //这句话保证了每个数只会被筛O(1)次,只会被自己最小的质因子筛掉
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	b[1]=1;
    	judge(n);
    	while(m--)
    	{
    		scanf("%d",&x);
    		if(b[x]) printf("No
    ");
    		else printf("Yes
    ");
    	}
    	return 0;
    }    
    

      这个题,这份代码一定要注意的是bool b数组0和1对应的到底是还是不是质数!

    欧拉函数

      

         公式?

    线性筛法求欧拉函数

    for(int i=2;i<=n;++i)
    {
    	if(!b[i]) 
    	{
    		pri[++num]=i;
    		olar[i]=i-1;
    	}
    	for(int j=1;j<=num;++j)
    	{
    		if(i*pri[j]>n) break;
    		b[i*pri[j]]=1;
    		if(i*pri[j]!=0)
    			olar[i*pri[j]]=olar[i]*(pri[j]-1);
    		if(i%pri[j]==0)
    		{
    			olar[i*pri[j]]=olar[i]*pri[j];
    			break;
    		} 
    	}
    }
    //相当于线性筛素数的时候顺道求出欧拉函数
    

      非常有必要解释一下pri和olar这两个数组的意义,:

      pri记录1~n中所有的素数,也就是说,pri[i]表示的是第i个质数是多少,;

      olar当然就是欧拉函数了,olar[i]表示的是1~i中质数的个数,;

    EG:

      给出一个数n,求比n小且与n互质的数的和,n<=10^7;

      答案就是n*olar[n]/2,互质的数是一对的,

      gcd(a,n)=gcd(n-a,n)=1;

    组合数

      

      有序:n=3有6(n!)种排列,

      无序:n!种算作一种,那么就有(n!-1)种都是重复的;

      ※放挡板问题;(不能解决0)

      ※0的话就先都+1,最后再-1;

      先要知道杨辉三角:  

      1
      1 1
      1 2 1
      1 3 3 1
      1 4 6 4 1
      1 5 10 10 5 1

      杨辉三角的性质:

      第n行的元素个数有n个;
      第n行的所有元素之和为2*(n-1)?;
      第n行第m个数的值为C(n-1, m-1),其中C为组合数;
      (a+b)n展开后的各项系数等于第n+1行的值;
      第n行第m个数的奇偶判断,及C(n-1,m-1)的奇偶判断:
      (m-1)&(n-1)==(m-1)? 奇:偶;
      (证明见http://www.cnblogs.com/Muia/p/5746491.html)

      杨辉三角的应用:

      最好的应用之一就是减少求组合数的复杂度:
      将杨辉三角的值打印出来后,只需要查表即可得到正确结果,
      这个对于求排列组合数非常有用;

    另外一种Lucas定理

      #%……¥%……&¥#@¥%

      (常与数位DP结合,)

    求组合数的另一种方法

      给定o<=n<=m<=10^5,1<p<10^9;

      q组数据,计算C(m,n)mod p;

      ※预处理出阶乘,和阶乘的逆元,直接计算???;O(m+n+q);

    一些组合数有用的公式

      

      要特别知道的是5和4;

    容斥原理

      eg:一道小学奥数,

      

      

      答案为:4+17+18+15-6-6-5+2=39

      容斥原理图:

      

      

    斐波那契数列  

      f(0)=1,f(1)=1;
      f(n)=f(n-1)+f(n-2),n>=2

    卡特兰数  

      C(1)=1;
      C(n+1)=C(1)C(n)+C(2)C(n-1)+...+C(n)C(1)

    Eg:

      n个数要进栈然后出栈,问出栈顺序有多少种? 

       设f(n)为n个数的答案,枚举最后一个出栈的为k,那么

      

      P1044 卡特兰数,栈(两种操作)

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int main()
    {
        int n;
        long long int f[100000];
        cin>>n;
        f[0]=f[1]=1;
        for(int i=2;i<=n;i++)
            f[i]=f[i-1]*(4*i-2)/(i+1);
        cout<<f[n];
    }
    

    Eg:

      给定n个节点,求能生成多少个不同形状的二叉树?

      设f(n)为n个数的答案,枚举左子树大小为k

      

    卡特兰数通项公式

      C(n+1)=C(2n,n)-C(2n,n-1)

    折线法

      例题%……&&*@¥¥%……

      走方格,不能穿过对角线#%……&##@%

    错排

      一个有n个元素的序列,若这n个元素都不在自己原来的位置上,那么这样的排列就被称为错排;

      i个元素的错排方案数为D(i);

    推导公式

      D(n)=(n-1)[D(n-1)+D(n-2)]

      D(1)=0,D(2)=1;

      推导方法:

      第一步将n放到位置k,k<n,有n-1种放法;

      第二步若将k放到位置n,那么就有D(n-2)种放法,否则就有D(n-1)种放法;

    Eg:

      有n本书,n个位置,每一本书放一个位置;求恰好有m本书放对位置的方案数;

      答案为:C(n,m)*D(n-m);

    高斯消元

       最大用途:解多元一次方程组;

        

     

    抑或高斯消元

        

         相当于把原来方程组中的+和-换成^操作;

    概率与期望

      定义?

      举一个简单的例子:你有0.8的概率拿50分,0.2的概率拿100分,你的期望得分便为0.8*50+0.2*100=60分

       0.8,0.2就是概率,60就是期望;

    贝叶斯公式

      

      两个独立(没有关系的)事件的概率可相加;

      E(A+B)=E(A)+E(B);

      P(B|A):表示在A一定发生的情况下,B发生的概率;

      ①:如果AB独立,P(B|A)=P(B);

      ②:P(B|A)*P(A)=P(AB)(贝叶斯)

      P(AB):若两个独立,P(AB)=P(A)*P(B);

    Eg:

      

     

      这个题目比较简单,我们只需要想:已经拿走一个白球,还剩9个,那么再拿到一个红球,概率就为3/9=1/3

      但是这只是比较简单的问题,而对于较复杂的问题来说,还是要依靠贝叶斯公式,

      此题方法为:A表示第一次拿到白球,B表示第二次拿到红球,

       P(A)=1/10 P(AB)=1/30 P(B|A)=P(AB)/P(A)=1/3

    DP类型的期望题 

      一般有两种设法
      f(i)表示i到终点的期望,然后按照i递减来推。
      f(i)表示起点到i的期望,然后按照i递增来推。 

      一般前者用得较多

      例如我要从0号点到n号点,一次可以走一步或者两步,问到达终点的期望;

      

      初始化f(n)=0,

      f(i)=p1*(f(i+1)+1)+p2*(f(i+2)+1);

    矩阵乘法

      一个n行m列的矩阵A*一个m行p列的矩阵B=一个n行p列的矩阵C;

      A*B  A第一行*B第一列

      公式:

      

      时间复杂度O(nmp),

      性质:一般不满足交换律,满足结合律;A*B*C=A*(B*C)

      那么结合律有什么好处呢?答曰:相同的东西合到一起用快速幂;

      比如:求A*B*A*B*A*B ,就可以计算(A*B)*(A*B)*(A*B)

    Eg:

      求斐波那契第n项mod p,n<=10^15

      我们把它看做一个1*2的矩阵,也就是:

      求得?也就是矩阵B为

      所以啊,

      

      也就是

      矩阵C的左上角就是答案,

      矩阵乘法的功能之一:优化DP;

    Eg:

      现在要向前走n个单位的距离,每一步的步长为[1,k]个单位,问走完n个单位可以有多少种不同的方法;

      n<=10^15,k<=7;

      和上面类似,如果k=4,那么f[n]=f[n-1]+f[n-2]+f[n-3]+f[n-4]

      转移矩阵就为:

     

      k=3时,

      

    Eg※:

      给你三个N*N的矩阵A B C,问A*B在mod p意义下是否等于C;n<=1000

      直接判断的话是1000^3,过不了,我们尝试构造几个1*n的随机矩阵D,

      判断D*A*B是否等于D*C,每次判断的时间复杂度为O(n^2);

      

      矩阵D是为了减少复杂度的,可以降到O(n^2),间接判断A*B是否=C

      

     

     

     

     

     

     

     

     

  • 相关阅读:
    Java String, StringBuffer和StringBuilder实例
    java中字符串的比较
    java中子类继承父类时是否继承构造函数
    Java中抽象类和接口的用法和区别
    与(&)、非(~)、或(|)、异或(^)
    Linux03
    Linux02
    Linux01
    力扣算法题
    算法 栈、队列、二分查找
  • 原文地址:https://www.cnblogs.com/Mary-Sue/p/9735348.html
Copyright © 2020-2023  润新知