超简单的数论入门题

17 篇文章 1 订阅
6 篇文章 0 订阅

选定方向了,这篇博客将伴随我学习数论和某些数学知识

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

用途:求两个数最大公约数

公式:a%b=b%(a%b)

代码 :    ll gcd(ll a,ll b) {return !b?a:gcd(b,a%b);}   ///函数形式

2.拓展欧几里得

用途:求不定方程最小解( 方程应满足ax+by=gcd(a,b),否则无解 )

公式推导:(嫖的)

假设 ax1 + by1= gcd(a,b);

假设 bx2 + (a % b)y2= gcd(b,a % b);

根据朴素的欧几里德原理有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。

我们可以通过不断递归调用求解。

代码:

ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b){x=1,y=0;return a;}
    ll ans=exgcd(b,a%b,x,y);
    ll t=x;x=y;y=t-a/b*y;
    return ans;
}

x,y是一组解,返回的ans是gcd(a,b)

x,y的通解为

kx=b/ans

ky=-a/ans

*x=x+kx*n   *y=y+ky*n    (n为任意值) 

例题:青蛙的约会 

题目链接:http://poj.org/problem?id=1061

题干:

两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。 
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。 

题解:

设跳t次后,两青蛙相遇,则满足方程      (x+t*m)%L=(y+t*n)%L  

化简下得      x-y=(n-m)*t+kL满足ax+by=c的关系式  如c整除gcd(a,b)则方程有解,注意这里的c是h*gcd(a,b),所以想直接调用函数还得等式两边同时乘  c/gcd(a,b)

代码:

#include <iostream>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b){x=1,y=0;return a;}
    ll ans=exgcd(b,a%b,x,y);
    ll t=x;x=y;y=t-a/b*y;
    return ans;
}
int main()
{
    ll x,y,m,n,l,p,c,a,b;
    cin>>x>>y>>m>>n>>l;
    a=n-m;  c=x-y;  b=l;
    if(a<0) { a=-a;c=-c; }
    p=exgcd(a,b,x,y);
    if(c%p!=0)
        cout<<"Impossible\n";
    else
    {
        x=x*c/p;
        ll t=b/p;
        if(x>=0) x=x%t;
        else x=x%t+t;
        cout<<x<<endl;
    }
    return 0;
}

 

3.欧拉筛数

这里不介绍其他的筛质数方法了

原理:

对于任意一个合数,我们可以拆成最小质数*某个数字的形式。我们枚举i,然后再从第一个质数开始枚举,进行筛选。 为了保证每个合数只被最小质因数筛选,当我们枚举的质数可以整除i时,如果再往大里枚举,枚举的质数就不可能是最小质数了

代码:

int cntprime = 0;
for (int i = 2; i <= n; i++)
{
    if (!flag[i]) prime[++cntprime] = i;
    for (int j = 1; j <= cntprime && prime[j] * i <= n; j++)
    {
        flag[i * prime[j]] = true;
        if (i % prime[j] == 0)
            break;
    }
}

时间复杂度极其接近于O(n);

 

4.逆元及费马小定理

在计算机运算过程中,分数是一个很难计算和保留精确度的东西,所以对于分数而言,我们一般会表示为mod某数的逆元

(a*x)%mod=1  x称为a在mod下的逆元

费马小定理就是   当加入p为质数且   a,p互质则    a^(p-1)=1(mod p)

即:在求某数的逆元的时候      如果mod是质数的话  则只需计算   a^(p-2)%p;

 

5.快速幂与矩阵快速幂

参考另一篇:https://blog.csdn.net/permi_yaxileni/article/details/98319067

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //看心情更,不过会一直更的

 

 

6.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值