- 2022tysc0250 的博客
乘法逆元&P、NP类问题
- 2023-8-25 15:04:14 @
数学上的乘法逆元就是倒数,即 的逆元是 (或 ),也即与 相乘得 的数。若 ,则 是 的乘法逆元。
这里我们讨论关于取模运算的乘法逆元,即对于整数 ,与 互质的数 作为模数,当整数 满足 时,称 为 关于模 的逆元,代码表示就是 a * x % b == 1
。
在算法竞赛中,经常会遇到求解数据很大,则输出模 的解这类要求。加法、减法、乘法等操作,基于同余理论直接取模即可。但遇到除法时,某步中间结果不一定能完成整除,就无法求解了。
举个例子:求 对 取模的结果。我们直接算出 的结果是 ,对 取模得最终答案是 。
但我们通常面对的问题是中间结果超过long long
甚至int
的范围,而不得不在每一步基于同余理论取模,我们用这个例子尝试一下:
还是求
- 这个中间结果再做 无法整除,就无法进行下去了。
但我们可以求出除数 关于模数 的逆元 (根据逆元定义, 符合 ),从而,用乘以 代替除以 。
上述第二步除法变乘法:,
从而也计算出了正确的结果 。
乘法逆元的作用就是:
设 是一个天文数字,、 已知,预期要计算(假设答案为 )
对于 的逆元 ,能够满足
在有些问题中,无法计算最终值很大的 ,只能得到基于同余的一个中间值 来计算 ,而 可能无法整除 ,就可以用 的逆元 ,来计算 。
故而我们需要一个算法求除数的取模逆元,从而在四则运算取模的任务中,用逆元将除法转为乘法。
#include<cstdio>
using namespace std;
void exgcd(int a,int b,int &x,int &y){
if(b==0){x=1,y=0;return;}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
int get_inv(int a,int p){
int x=1,y=0;
exgcd(a,p,x,y);//x=a_inv,a*a_inv+p*y=1
return (x%p+p)%p;
}
int a,p;
int main(){
scanf("%d%d",&a,&p);
printf("%d",get_inv(a,p));
}
以下copy自百度百科(6
乘法逆元,是指数学领域群 中任意一个元素 ,都在 中有唯一的逆元 ,具有性质 ,其中 为该群的单位元。
例如: 关于 模 的乘法逆元为多少?
这个方程等价于求一个 和 ,满足
其中 和 都是整数。
若 , 则称 关于 模 的乘法逆元为 。也可表示为 。
当 与 互素时, 关于模 的乘法逆元有解。如果不互素,则无解。如果 为素数,则从 到 的任意数都与 互素,即在 到 之间都恰好有一个关于模 的乘法逆元。
例如,求 关于模 的乘法逆元:
说明 与 互素,存在 关于 的乘法逆元。
因此, 关于模 的乘法逆元为 。
乘法逆元的定义及用途,以及求逆元的三种算法:扩展欧几里得、费马小定理、递推求逆元。
-
P类问题:存在多项式时间算法的问题,即在多项式时间内可解的问题
例如:冒泡排序,快速排序等问题
-
NP类问题:能在多项式时间内验证出一个正确解的问题,也就是说这个问题不一定在多项式时间内可解,但可以在多项式时间内验证
例如:大数分解问题,比如 这个数让你拆成两个数相乘,必须是三位乘以三位的,可能很久都解不出来(如果是一个很大很大的数的话),但是我告诉你这是 得到的,那么很简单就能在多项式时间内验证是否正确,这就是NP问题
-
NPC类问题:存在这样一个NP问题,所有的NP问题都可以约化成它
-
NP-Hard类问题:所有的NP问题都可以约化成它
c的