训练日志1

1.1整除:

     关于整除,可以理解为一个数是另一个数的倍数,核心都围绕在这个倍数上,如果已知a|b,那么一般都可以假设b=ak,然后进行推导.如果不能整除,往往会有一个余数r,假设b%a=r,那么b = ak+r,当遇到余数的时候,通过余数展开式进行推导也是一种比较常用的方法.

1.2同余:

         一般是在题目给定了模数下才会用到,但是有一些特殊情况比如数太大存不下,只考虑它在同余下的意义也是可以的。同余的运算基本上和四则运算差不多,只不过没有定义除法!涉及到除法就必须要用到逆元!比较常用的性质就是同幂性:a ≡ b (mod p) ---> a^n ≡ b^n (mod p).还有同乘性.幂数取模问题:若幂次不大,则直接快速幂运算即可(.若幂次很大,则用欧拉定理降幂)未看

快速幂运算:

      快速幂算法——可迅速求出a^b。其主要理论依据如下:

        1,当b为偶数时,a^b可以转为a^2的b/2次方。

        2,当b为奇数时,a^b可以转为a^2的b/2次方,再乘以a。

       而a^2的b/2次方,以可以使用上述方式转为a^4的b/4次方再乘以某个数。代码如下:

    

​
    private static int cifang(int a, int b) {

        int s = 1;

        while (b > 0) {

            if (b % 2 == 1) {//b=b>>1保证了在最后一步肯定会执行该if判断

                s = s * a;

            }

            a = a * a;

            b = b >> 1;

        }

        return s;

    }
​

        1.3最大公约数

   1.3.1辗转相除法(又称欧几里得法 原理:GCD(x,y)=GCD(x,y-x) )

       代码实现:

int GCD(int x,int y)
{
  return x==0? x:GCD(y,x%y);
}

  1.3.2二进制算法

算法效率

 只有移位和加减操作,抛弃了欧几里得算法的取模,大数据中效率很高(听说)

算法思想

为了说明Stein算法的正确性,首先必须注意到以下结论:

gcd(a,a)=a,也就是一个数和其自身的公约数仍是其自身。

gcd(ka,kb)=k gcd(a,b),也就是最大公约数运算和倍乘运算可以交换。特殊地,当k=2时,说明两个偶数的最大公约数必然能被2整除。

当k与b互为质数,gcd(ka,b)=gcd(a,b),也就是约掉两个数中只有其中一个含有的因子不影响最大公约数。特殊地,当k=2时,说明计算一个偶数和一个奇数的最大公约数时,可以先将偶数除以2。

算法步骤

1、如果An=Bn,那么An(或Bn)*Cn是最大公约数,算法结束

2、如果An=0,Bn是最大公约数,算法结束

3、如果Bn=0,An是最大公约数,算法结束

4、设置A1=A、B1=B和C1=1

5、如果An和Bn都是偶数,则An+1=An/2,Bn+1=Bn/2,Cn+1=Cn*2(注意,乘2只要把整数左移一位即可,除2只要把整数右移一位即可)

6、如果An是偶数,Bn不是偶数,则An+1=An/2,Bn+1=Bn,Cn+1=Cn(很显然啦,2不是奇数的约数)

7、如果Bn是偶数,An不是偶数,则Bn+1=Bn/2,An+1=An,Cn+1=Cn(很显然啦,2不是奇数的约数)

8、如果An和Bn都不是偶数,则An+1=|An-Bn|/2,Bn+1=min(An,Bn),Cn+1=Cn


int gcd(int a, int b)

{

if (a<b) swap(a,b);// 交换a,b的值,保证a>=b

if (b==0) return a;

if ((a&0x1)==0 && (b&0x1)==0) // a,b均为偶数(避免使用除法和取模运算)

return 2*gcd(a>>1, b>>1);

if ((a&0x1)==0 && (b&0x1)!=0) // a为偶数,b为奇数

return gcd(a>>1, b);

if ((a&0x1)!=0 && (b&0x1)==0) // a为奇数,b为偶数

return gcd(a, b>>1);

if ((a&0x1)!=0 && (b&0x1)!=0) // a,b均为奇数

return gcd((a-b)>>1, b);

}

1.3.3最小公倍数

 定理:a,b两个数的最大公约数乘以他们的最小公倍数等于a和b本身的乘积


#include <iostream>

 

using namespace std;

int gcd(int a,int b)

{

    if(b==0)return a;

    else return gcd(b,a%b);

}

int main()

{

    int n,m;

    cin>>n>>m;

    int c=gcd(n,m);

    cout<<(n*m/c);

    return 0;

}

1.3.4扩展欧几里得算法

 来源:http://blog.csdn.net/leader_one/article/details/75222771

1.3.5求解线性同余方程

  线性同余方程
        
     对于方程 a*x+b*y=n;有整数解得充分必要条件是(n %(a,b)==0),这个定理这里就不证明了,数论书上都有。
     所以方程 a*x+b*y=n;我们可以先用扩展欧几里德算法求出一组x0,y0。也就是a*x0+b*y0=GCD(a,b);然后两边同时除以GCD(a,b),再乘以n。这样就得到了方程a*x0*n/GCD(a,b)+b*y0*n/GCD(a,b)=n;我们也就找到了方程的一个解。
     还有一个定理:若(a,b)=1,且x0,y0为a*x+b*y=n的一组解,则该方程的任一解可表示为:x=x0+b*t,y=y0-a*t;且对任一整数t,皆成立。(这个证明比较简单,就不写了)
     这样我们就可以求出方程的所有解了,但实际问题中,我们往往被要求去求最小整数解,所以我们就可以将一个特解x,t=b/GCD(a,b),x=(x%t+t)%t(相当于绝对值);就可以了。

猜你喜欢

转载自blog.csdn.net/sunpeishuai/article/details/81292899
今日推荐