知识点:乘法逆元,逆元的求法,二元一次方程求通解,a的n次方求余数
乘法逆元的概念类似于倒数( ax=1,a−1=x ),不过是在取余数的情况下的倒数。
如果 (a×x)%p=1 ,则称x是a模p的逆元。另一种记法: ax=1( mod p) ,即等式两边去膜 p 运算。显然 x 有无限多个(如果有)。
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5685
逆元的作用:已知 F%p和a%p 的值,求 (Fa)%p (我们不知道 F和a 的值,且 F%a=0 )。
a 模 p 的乘法逆元 b ,相当于模 p 运算中的 a−1
模 p 运算中,乘以 b 相当于除以 a ,即乘以 a−1 。
下面该学习如何求解乘法逆元
档模 p 比较小的时候,我们可以枚举 1到p−1 ,判断 ax=1 ( mod p) 即可。如果有逆元,那么 1到p−1 一定存在逆元。因为任何大于p的逆元都可以写成 x=yp+x%p ,由 ax=ayp+a(x%p)=a(x%p)=1( modp) 。所以 x%p 是 a 关于模 p 的逆元,且 x%p 小于 p 。
首先要了解欧几里得算法,也就是辗转相除法, gcd(a,b)=gcd(b,a%b) ,每次迭代问题规模都会减小,算法复杂度是 log n 。扩展欧几里得算法是利用辗转相除法的逆过程来得到乘法逆元的过程。求解 ax=1( mod p) ,相当于求解 ax=py+1,即ax+py=1 ,其中 x和y 为整数。前面说过, a和p 互素才有乘法逆元,所以 gcd(a,p)=1 ,所以相当于求解 ax+py=gcd(a,p) 。
上述过程求解ax+py=gcd(a,p)的过程,并不要求gcd(a,p)一定等于1。由上述过程 ,我们可以推广得到求解任意二元一次方程ax+by=c的解。
扩展欧几里得算法代码如下:
int exgcd(int a, int b, int &x, int &y)
{
if(b==0){
x = 1;
y = 0;
return a;
}else{
int _gcd = exgcd(b,b%a,x,y);
int tmp = x - (a/b)*y;
x = y;
y = tmp;
return _gcd;
}
}
x = (x % p + p) % p; // 通常需要求解最小的正整数逆元解ax=1(mod p)
// 再次提醒a和p互素,即gcd(a,p) = 1
费马小定理:假如p是质数,且 gcd(a,p)=1 ,那么 ap−1≡1 ( mod p) ,即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。
由 ap−1=1 ( mod p) 很容易得到 a∗ap−2=1 ( mod p) ,那也就是 a 的逆元是 ap−2 。
需要注意的是需要判断 a和p 是否互素,如果用gcd来判断的话,那还不如直接用扩展欧几里得算法。
由前面可知,当 p 为素数时, 1到p−1 都存在模 p 的乘法逆元。
采用递推的方法来求解所有 1到p−1 的逆元。如下:
const int p = 13;
int inv[p+2];
inv[1] = 1;
for (int i = 2;i < p;i++)
inv[i] = ((p - p / i)*inv[p%i]) % p;
对于1到p的都只存在一个小于p的逆元,为什么?
如求 20172017%1777 或者 2100%9973 的值:
long long remainder_of_an_exponential_recur(int a, int b, int c)
{ // 递归求 (a^b)%c
if (b == 0)
return 1;
long long tmp = remainder_of_an_exponential_recur(a, b >> 1, c);
if (b & 1)
return (tmp*tmp*a) % c;
else
return (tmp*tmp) % c;
}
long long remainder_of_an_exponential_loop(int a, int b, int c)
{ // 递推求 (a^b)%c
long long res = 1;
long long tmp = a;
while (b)
{
if (b & 1) res = (res*tmp) % c;
tmp = (tmp*tmp) % c;
b >>= 1;
}
return res;
}
如果除数是 2i ,求余数。这个比较简单 a%2 也就是求 a 的二进制表示方式中的最后一位的值。 a%2=a%(21)=a & 20=a & 1 。 a%8 也就是求 a 的二进制表示方式中的最后三位的值。 a%8=a%(23)=a & (23−1)=a & 7 。以此类推 a%(2i)=a & (2i−1) 。
最后一个需要说的是公式: ab%p=a%(b×p)b%p。(其中a%b=0) 。这个公式一般都是在无法计算得到 a 的情况下使用的,这个公式当然也可以两边乘以 b 的逆元。这个公式画图理解比较好,如下所示:
在ALL X问题中:http://acm.hdu.edu.cn/showproblem.php?pid=5690。
要求检验一个全由 x 组成的 m 位数字 F(x,m) 是否可以满足等式 F(x,m) mod k=c 。
既可以利用余数有限重复循环的方法,即按照除法的方法依次计算余数,如果余数重复,那么就开始进入了循环,而余数的个数是有限的,小于k个。这和求 a/b 的小数表示形式是一样的(它是无限的添加0,本题中是无限的添加x)。
另一种方法是求解 F(x,m) ,容易知道 F(x,m)=x×10m−19 ,那么 F(x,m) mod k=[(x%k)×10m−19%k]%k ,相当于求解 10m−19%k ,利用上述公式可以得到 10m−19%k=(10m−1)%(9k)9%k=[10m%(9k)]−19%k 。而 [10m%(9k)] 可以利用a的n次方取余的方法来求解。
求 an ,可以用快速幂乘,a可以是矩阵。
an=an/2∗an/2,n是偶数
a^{n}=a^{n/2}*a^{n/2}*ahttps://www.baidu.com/s?ie=UTF-8&wd=快速幂乘&tn=98012088_4_dg&ch=10
,n是奇数数
参考:
http://blog.csdn.NET/tsaid/article/details/7365936
http://www.cnblogs.com/ka200812/archive/2011/09/02/2164404.html
https://wenku.baidu.com/view/c1b06ea60029bd64783e2c63.html
http://blog.csdn.net/stcyclone/article/details/52081822