以下内容均为牌王(可点开链接哦)所教,此人无敌!!!感谢牌王的细心教导,嘿嘿嘿
逆元可以说是倒数概念的推广,对于正整数a,p,若有ax≡1(mod p),则称x是a关于模p的逆元。例如:
那么为什么要有逆元呢?逆元有什么作用?
加减乘与模运算的顺序交换不会影响结果,即可用分配律,但是除法呢?答案是不行的,那么有什么办法可以完成除法与模运算之间的运算呢,这时候就是主角逆元登场了。
例如求解(a / b) mod p
先求出b关于p的逆元c,即b*c≡1(mod p),将其带入上式得
(a / b * b * c)≡ 1 (mod p) -> (a * c)≡1(mod p)
即可将除法转化成乘法,是不是很有趣?
逆元存在的条件:a与p互质,即gcd(a,p)=1。
代码如下:
ll FPM(ll x,ll power,ll mod)
{
ll ans = 1;
while(power)
{
if(power & 1)
{
ans = (ans * x) % mod;
}
x = (x * x) % mod;
power >>= 1;
}
return ans % mod;
}
ax≡1(mod p)->ax = pk + 1
当a,p互质时,gcd(a,b)=1,即将上式转化为
当求解gcd(a,b)时,递归结束的条件为b=0,得出a=gcd(a,b),进一步得出x=1,所以对上式使用递归时,结束条件为b = 0,并使x=1,y=0。
即
if(!b)
{
x = 1;
y = 0;
return a;
}
紧接着一直回朔,最后得出x的值,并且还可以求出a和b的最大公约数,是不是一举两得?
回朔过程的解析:
ax1+by1=gcd(a,b)
ax2+by2=gcd(a,b)
将第二个式子变化一下为
bx2+(a-a/bb)y2=gcd(a,b)->ay2+b(x2-a/by2)=gcd(a,b)
则x1=y2, y1=x2-a/by2
那么不断回朔回去,即可得到x。
得出x后,如果为负数,则需要(x % mod + mod) % mod使其变为正
当然,可以将其推广则可求出任意二元一次方程的最小解,不过也是有条件的,例如
求ax+by=c的解,当且仅当c/gcd(a,b)!=0时,x有最小解。
代码如下:
typedef long long LL;
LL exgcd(LL a,LL b,LL &x,LL &y) //扩展欧几里得算法
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
LL ret = exgcd(b, a%b, x, y);
ll t = x;
x = y;
y = t - a / b * x;
return ret;
}
LL inv(int a, int mod) //求a在mod下的逆元,如果不存在返回-1
{
LL x, y;
LL d = exgcd(a, mod, x, y);
return d ? (x % mod + mod) % mod : -1;
}
过程如下:
这里就不再详细描述了…直接上代码!!!(打字太累了)
代码如下:
ll inv[3000005] = {0 , 1}; //n等于1时,关于mod的逆元就为1
int main()
{
ll n, mod;
scanf("%lld%lld",&n,&mod);
printf("1\n");
for(int i = 2;i <= n; i++) // 从二开始,防止改变inv[1]的值
{
inv[i] = mod - (mod / i) * inv[mod % i] % mod;// 这一步important // 加个mod是为了防止逆元为负
printf("%lld\n",inv[i]);
}
return 0;
}
很早就想自己写点东西记录自己的学习过程,可以太懒了,而且语言组织也不好,不过,在数论方面,每次我遇到问题,牌王都会帮我解答,非常感谢牌王!!!那么这次我就将这篇博客写好,“送”给你来表达我对你的爱?