选定方向了,这篇博客将伴随我学习数论和某些数学知识
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.