暑假训练日志—数论

102 篇文章 1 订阅
3 篇文章 0 订阅

数论—最大公约数

辗转相除法(欧几里得算法)

原理:GCD(x , y)= GCD(x , y-x)

核心:不断将两数规模变小,最后实现对数时间内把问题变换到能直接判定解的规模

代码实现:

int GCD(int x,int y)

{

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

}

二进制算法

通过不断去除因子2降低常数实现提高GCD的效率,避免了欧几里得算法中对余数的计算过程

若x=y,则GCD(x,y)=x,否则: 
(1)若x,y均为偶数,则GCD(x,y)=2*GCD(x/2,y/2); 
(2)若x为偶数,y为奇数,则GCD(x,y)=2*GCD(x/2,y); 
(3)若x为奇数,y为偶数,则GCD(x,y)=2*GCD(x,y/2); 
(3)若x,y均为奇数,则GCD(x,y)=GCD(x-y,y); 

代码实现:

inline int GCD(int x,int y)//欧几里得二进制算法优化

{

    int i,j;

    if(x==0)return y;

    if(y==0)return x;

    for(i=0;0==(x&1);i++)x>>=1;//去掉所有的2

    for(j=0;0==(y&1);j++)y>>=1;//去掉所有的2

    if(j<i)i=j;

    while(1)

    {

        if(x<y)x^=y,y^=x,x^=y;//若x<y交换x,y

        if(0==(x-=y))return y<<i;

        //若x==y,gcd==x==y(就是在辗转减,while(1)控制)

        while(0==(x&1))x>>=1;//去掉所有的2

    }

}

x>>=1  右移运算符,将x的二进制表示向右移动1位,最高位补0,将此结果再赋值给x。

<<= 同理

[/demo]



#include<iostream>

using namespace std;

typedef long long ll;

inline ll abs(ll x){

    return x<0?-x:x;

}

inline ll min(ll a,ll b){

    return a<b?a:b;

}

inline ll gcd(ll a,ll b){

    if(a==0)return b;

    if(b==0)return a;

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

    else if(!(a&1))return gcd(a>>1,b);

    else if(!(b&1))return gcd(a,b>>1);

    else return gcd(abs(a-b),min(a,b));

}



int main(){

    ll a,b;

    cin>>a>>b;

    cout<<"gcd="<<gcd(a,b);

    return 0;

}



[/demo]

 

扩展欧几里得算法

用途:已知(a,b),求解一组(p,q),使得p*a+q*b=GCD(a,b)

首先呢,可以看出:a = gcd(a,b), b = 0 是该式的一个特解; 
然后,根据欧几里得算法的原理可以得出:bx + (a%b)y = gcd(a,b); 
又因为, a%b = a - (a/b)*b (a/b 为整除关系
所以原式化为: bx + (a - (a/b)*b)y = gcd(a,b); 
整理得: ay + b * (x - (a/b) * y) = gcd(a,b); 

代码实现:

int extend_gcd(int a, int b, int &x, int &y)

{

    if(b==0)

    {

        x = 1;

        y = 0;

        return a;

    }

    int r = extend_gcd(b, a%b, y, x);

    y -= a/b*x; //这里已经是递归,回溯的过程了,x,y已经颠倒了

    return r;

}




 

[/demo]



#include<bits/stdc++.h>

int extended_gcd(int a,int b,int &x,int &y)

{

    if(!b)

    {

       x=1;

       y=0;

       return a;

    }

    int r=extended_gcd(b,a%b,y,x)

    y-=a/b*x;

    return r;

}

int main()

{

    int a,b,x,y;

    scanf(“%d%d”,&a,&b);

    z=extended_gcd(a,b,x,y);

    printf(“%d%d%d\n”,z,x,y);

    return 0;

}





[/demo]

 

求解线性同余方程

定理1:对于方程a*x+b*y=c,有整数解的充分必要条件是:c%GCD(a,b)=0。

定理2:若GCD(a,b)=1,且x0,y0为a*x+b*y=c的一组解,则该方程的任一解可表示为:x=x0+b*t,y=y0-a*t,且对任一整t,皆成立。

代码实现:

int extended_euclid(int a,int b,int&x,int&y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int d=extended_educlid(b,a%b,x,y);
    int temp=x;
    x=y;
    y=temp-a/b*y;
    return d;
}
//用扩展欧几里得算法解线性方程ax+by=c;
bool linearEquation(int a,int b,int&x,int&y)
{
    int d=extended_euclid(a,b,x,y);
    if(c%d)return false;
    int k=c/d;
    x*=k;              //+t*b;
    y*=k;              //-t*a;
    //求得只是其中一个解
    return true;
}

训练心得:

        一天下来,感觉没有收获很多东西。上午花了一个小时左右的时间把整本书浏览了一遍(个人习惯,看书前习惯上把翻一翻整本书,知道大体内容),然后下手看数论部分的内容。数论部分一共11小节,做了简单的计划,因为周二下午打比赛,所以计划周一和周三每天看4小节,周二看3小节。但一天下来,只看了前三节,前三节内容相对后面几节来说还是简单些,但是看完后也是似是而非,恍恍惚。进度没赶上,深度也差远了,似乎刚学这本书的这道坎很难迈过去(终于明白老师说的这次训练强度很大,要做好心理准备的意思了)。反思一下今天,最耗时的就是在最大公约数这一节中的二进制算法、扩展欧几里得算法、求解线性同余方程这几部分,每一部分都查看了几篇博客(讲真,只看书上的内容看半天还是一脸懵,这也是一本数论书压缩到几十页的弊端)参考着博客看知识点还是有用处的,但是熟练程度离老师要求还差远了。

       所以,方法只有一个......

       加班

       还有,坐上一天腰是真的酸。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值