乘法逆元:修订间差异
跳转到导航
跳转到搜索
无编辑摘要 |
无编辑摘要 |
||
| 第33行: | 第33行: | ||
} | } | ||
return res; | return res; | ||
} | |||
</syntaxhighlight> | |||
===扩展欧几里得算法=== | |||
====累赘但好懂的写法==== | |||
<syntaxhighlight lang="cpp" line> | |||
// 返回 ax+by=gcd(a,b) 的解 <x,y> | |||
pair<int, int> exGCD(int a, int b) | |||
{ | |||
// ax+0y=a | |||
if (b == 0) | |||
return {1, 0}; | |||
pair<int, int> nxt = exGCD(b, a % b); | |||
int xx = nxt.first; | |||
int yy = nxt.second; | |||
int x = yy; | |||
int y = xx - a / b * yy; | |||
return {x, y}; | |||
} | |||
</syntaxhighlight> | |||
====简化一点的写法==== | |||
<syntaxhighlight lang="cpp" line> | |||
// 返回 ax+by=gcd(a,b) 的解 <x,y> | |||
pair<int, int> exGCD(int a, int b) | |||
{ | |||
// ax+0y=a | |||
if (b == 0) | |||
return {1, 0}; | |||
pair<int, int> nxt = exGCD(b, a % b); | |||
return {nxt.second, | |||
nxt.first - a / b * nxt.second}; | |||
} | |||
</syntaxhighlight> | |||
====常见的写法==== | |||
返回 gcd,引用类型的参数传递解 | |||
<syntaxhighlight lang="cpp" line> | |||
int exGcd(int a, int b, int &x, int &y) | |||
{ | |||
if (b == 0) | |||
{ | |||
x = 1, y = 0; | |||
return a; | |||
} | |||
int xx, yy; | |||
int gcd = exGcd(b, a % b, xx, yy); | |||
x = yy; | |||
y = xx - (a / b) * yy; | |||
return gcd; | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| 第45行: | 第100行: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==扩欧求逆元== | |||
<syntaxhighlight lang="cpp" line> | |||
// a 在模 b 意义下的逆元(gcd(a,b)==1) | |||
int inv(int a, int b) | |||
{ | |||
pair<int, int> ans = exGCD(a, b); | |||
// a * ans.first + b * ans.second = 1 | |||
// a * ans.first === 1 (%b) | |||
return (ans.first % b + b) % b; | |||
} | |||
</syntaxhighlight> | |||
==线性求逆元== | |||
<syntaxhighlight lang="cpp" line> | |||
inv[1] = 1; | |||
for (int i = 2; i <= n; i++) | |||
inv[i] = (p - p / i) * inv[p % i] % p; | |||
</syntaxhighlight> | |||
[[分类:代码模板]] | [[分类:代码模板]] | ||
2026年2月6日 (五) 03:46的版本
前置
快速幂
递归版
// a 的 b 次方在模 p 意义下的结果
int quick_pow(int a, int b, int p)
{
if (b == 0)
return 1;
int x = quick_pow(a, b / 2, p);
if (b % 2 == 0)
return x * x % p;
return x * x % p * a % p;
}
非递归版
// a 的 b 次方在模 p 意义下的结果
int quick_pow(int a, int b, int p)
{
int res = 1;
while (b > 0)
{
if (b % 2 == 1)
res = res * a % p;
b /= 2;
a = a * a % p;
}
return res;
}
扩展欧几里得算法
累赘但好懂的写法
// 返回 ax+by=gcd(a,b) 的解 <x,y>
pair<int, int> exGCD(int a, int b)
{
// ax+0y=a
if (b == 0)
return {1, 0};
pair<int, int> nxt = exGCD(b, a % b);
int xx = nxt.first;
int yy = nxt.second;
int x = yy;
int y = xx - a / b * yy;
return {x, y};
}
简化一点的写法
// 返回 ax+by=gcd(a,b) 的解 <x,y>
pair<int, int> exGCD(int a, int b)
{
// ax+0y=a
if (b == 0)
return {1, 0};
pair<int, int> nxt = exGCD(b, a % b);
return {nxt.second,
nxt.first - a / b * nxt.second};
}
常见的写法
返回 gcd,引用类型的参数传递解
int exGcd(int a, int b, int &x, int &y)
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
int xx, yy;
int gcd = exGcd(b, a % b, xx, yy);
x = yy;
y = xx - (a / b) * yy;
return gcd;
}
费马小定理求逆元
// a 在模 p(质数) 意义下的逆元
int inv(int a, int p)
{
return quick_pow(a, p - 2, p);
}
扩欧求逆元
// a 在模 b 意义下的逆元(gcd(a,b)==1)
int inv(int a, int b)
{
pair<int, int> ans = exGCD(a, b);
// a * ans.first + b * ans.second = 1
// a * ans.first === 1 (%b)
return (ans.first % b + b) % b;
}
线性求逆元
inv[1] = 1;
for (int i = 2; i <= n; i++)
inv[i] = (p - p / i) * inv[p % i] % p;