逆元
扯一点没有多大用的东西
-
在数论里面,我们通常不把倒数叫做倒数,而叫做逆元(纯属装13)
-
逆元的作用是非常非常大的,下面我们来看点easy的栗子
某些性质
-
前面三个都是对的
(不需要证明~) -
But——
(a÷b)modp≠((amodp)÷(bmodp))modp
(上面的÷是整除)
- 随便举个例子就知道它不成立
随便搞一下
这是不是说我们对除法下的大数模操作就毫无办法了?答案是no
-
为了方便,先来看看一些小学or初中级别的东东
-
比如说有条等式
①ax=1 - 明显x=1a,没毛病,恩然后我再加一个条件
-
那么现在x就不一定等于1a了
-
对于①式,我们就把x看成1a,而②式加了一个同余p的条件(mod p)
- 这时候,我们不把x看成倒数。这时的x为a关于p的逆元
(注意,当且仅当(a,p)=1且p为质数时,x才存在)
又是一个栗子
- 在这里,5和13的作用是一样的(乘3再模7都是1),所以,5是3关于7的逆元
(注意一点,除了α=5,没有其他整数α满足3α≡1(mod7),可以手玩试试,所以说逆元是唯一的)
逆元的蛋用
-
前面说了一些东东了
-
相信逆元的定义了应该很好懂
-
我们不妨把x的逆元用inv(x)来表示,那么对于除法——
(a÷b)modp=(a×inv(b))modp=(amodp×inv(b)modp)modp
难搞的除法瞬间变成了乘法,秒变水了很多
逆元这东东怎么求
way one
基础数论里面有两条著名的定理:欧拉定理和费马小定理
-
欧拉定理:(当(a,n)=1时成立)
-
费马小定理:(当(a,p)=1且p为质数时成立)
(我难道会告诉你我两个都不会证明吗……)
很明显,费马小定理是可以从欧拉定理推过来的
当p为质数时φ(p)=p−1,代入欧拉定理即费马小定理
-
既然我们在谈论逆元,就把费马小定理两边同除以一个p
ap−2≡1/a(modp) -
attention to到一点就是1a是个小数,而等号左边是个整数,别忘了我们在说的是数论倒数
-
这时拍拍脑袋,想一想,我们突然发现应该把1a写成inv(a)——
- so——
我们可以用快速幂来求a的逆元,时间复杂度O(log2p)
code
long long inv(long long a,long long p)
{
long long t=1,b=p-2;
while (b)
{
if ((b%1)==1)t=t*a%p;
a=a*a%p;
b/=2;
}
return t;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
通常题目会让你求109+7取模,这方法可以说快到飞起
方法一用快速幂求逆元,容易上手,对于OI大多数的题目,足矣
way two
逆元还可以用扩展欧几里得来求,怎么求?一步一步来
首先要知道一个概念:贝祖定理,他的描述是
对于a,b>0且a,b∈N,必然存在整数x和y,使得ax+by=gcd(a,b)
-
比如我们现在要求a关于p的逆元(条件是a和p互质且p是质数)
-
代入贝祖定理,则
ax+py=1(因为a和p互质所以(a,p)=1)) -
给上面那个式子做点操作,两边各模一个p,得到
axmodp+pymodp=1modp∴axmodp=1modp∴ax≡1(modp) -
∴x是a关于p的逆元(其实y也是p关于a的逆元,可证,同理)
这里用扩展欧几里得exgcd(a,p,x,y),求出的x即为a的逆元
code
void exgcd(long long a,long long b,long long &x,long long &y,long long &z)
{
if (!b)
{
z=a;
x=1;
y=0;
return;
}
exgcd(b,a%b,y,x,z);
y-=x*(a/b);
}
long long inv(long long a,long long b)
{
long long x,y;
exgcd(a,b,x,y);
return (x%p+p)%p;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
扩展欧几里得可谓比较牛,优点是用途多,能求gcd能求逆元能解线性方程
对于广大OIers是把利器,学会是必须的
way three
最后一种方法更简单更好打更好理解:递归
先来一发证明(网上找的)
-
有了这个等式,我们就可以用递归来求inv(a)了
-
递归出口inv(1)=1,因为1的逆元就是1
递归code
long long inv(long long a,long long p) //注意a要小于p,先把a%p一下
{
return a==1?1:(p-p/a)*inv(p%a,p)%p;
}
- 1
- 2
- 3
- 4
是不是短到爆炸?
-
因为pmoda后至多是12p,所以时间复杂度是O(log2p)
-
这种思想比费马小定理、扩展欧几里得优的地方是,他能用O(n)的时间预处理1~n的逆元
只不过把递归的式子改成递推而已
递推code
void init()
{
inv[1]=1;
for(int i=2;i<=n;i++)
{
inv[i]=(p-p/i)*1ll*inv[p%i]%p;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
这是方法三,个人感觉方法三在某些题目里更好用一些
易理解,码量低,时间复杂度也低,还能快速预处理,interesting——
一笑
-
逆元差不多没得好说的了
-
三种求逆元的方法其实都挺好用的
-
虽说我倾向于第三种啦,这个东西多少随意
-
欸第二种方法里的的扩展欧几里得是什么?顺便看看?
扩展欧几里得
先复习一下普通欧几里得算法吧
普通欧几里得算法又称辗转相除法,为gcd(a,b)=gcd(b,amodb)
-
我TM傻到连证明也要CO了 -
其实证明是没什么必要的,
图个开心罢了
证明一发?
-
先设a>b
-
a可以表示成a=kb+r(a,b,k,r∈N∗,r<b),∴r=amodb
-
设d是a和b的一个公约数,那么d|a,d|b
-
把r=a−kb两边各除以d,得到rd=ad−kbd=m
-
∵d|a,d|b∴m为整数,∴d|r也就是d|amodb
-
∴d是b和amodb的公因数
-
设d是b和amodb的公因数中的任意一个
-
∴d|b,d|amodb,设amodb=a−kb(k∈Z),∴d|a−kb
-
∴d|a,∴d|a,d|b,d|amodb,就是说a,b,amodb的所有公因数是一样的
-
公因数相同,最大公因数不也就相同了?∴gcd(a,b)=gcd(b,amodb)
辣鸡code
long long gcd(long long x,long long y)
{
return !y?x:gcd(y,x%y);
}
- 1
- 2
- 3
- 4
-
明显每mod一次,大的那个数至多是原来一半
-
所以最坏时间复杂度为O(log2n)
-
但是我
貌似查到欧几里得平均迭代次数为(12⋅ln2⋅lnN)π2+1.47(N为两个数中较小的那个)耶…… -
算了随意随意……
还是要学扩欧的
咋们不搞正经的
-
扩欧就是已经知道a,b,c,求解能使该等式成立的一组x,y
-
明显的啊,想要有整数解的话,必须满足gcd(a,b)|c
-
不然两边各除以gcd(a,b),等号左边是整数,而等号右边就是个分数了→_→您太强啦
不知道怎么求就给我右上角
-
设ax+by=gcd(a,b)
-
b=0时,明显gcd(a,b)=a,∴x=1,y=0
-
但当a,b≠0时,设ax1+by1=gcd(a,b),bx2+(amodb)y2=gcd(b,amodb)
-
∵gcd(a,b)=gcd(b,amodb),∴ax1+by1=bx2+(amodb)y2
-
∴ax1+by1=bx2+(a−⌊ab⌋⋅b)y2=ay2+bx2+⌊ab⌋⋅by2
-
根据某恒等定理x1=y2,y1=x2−⌊ab⌋⋅y2 -
所以x1和y1的值是由x2和y2来决定的
-
x2和y2的值通过递归得到
-
如此完美
不正经的code
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if (!b)
{
x=1;
y=0;
return a;
}
long long ans=exgcd(b,a%b,x,y);
int temp=x;
x=y;
y=temp-a/b*y;
return ans;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
其实差不多就是从上面CO过来的
-
直接调用
exgcd(a,b,x,y)
,结果是返回gcd(a,b) -
同时求出来的x和y能干嘛呢?
扩欧?有什么用?
扩欧一共有三种用途
purpose one
purpose two
purpose three
类欧几里得
随意随意
-
类欧几里得也是一种算法啦
-
它的样子很像欧几里得算法,所以叫做类欧
-
它可以解决O(n)时间的问题,然而它的时间复杂度和欧几里得是一样的,都是O(log2n)
-
下面进入类欧的
奇幻♂世界
三个函数和一个m
-
看官随便看看
-
反正类欧可以把这三个
明显O(n)的东东用O(log2n)搞掉
您也知道鄙人数论不好,所以这坑要多久填完我不好说
下面的除法都看成整除,不再添加⌊⌋了,每个除法都打一次太eggsache了
求f
- 分类讨论大法好!
a=0时
a≥c或b≥c时
a≤c且b≤c时
莫比乌斯反演
都说了度娘没用的还不信
呵呵莫比乌斯反演是数论数学中很重要的内容,在许多情况下能够简化运算,可以用于解决很多组合数学的问题
然而这仍旧没个卵用
-
网上并没有莫比乌斯反演的详细阐述,所以——
-
不墨迹,上车,飚上几圈再说
叫懵逼乌斯反演才对
-
首先定义
f(n)=∑d|ng(d) -
手推一波可以发现一些东东
白内障看不清浓硫酸滴眼睛就放大了再看
-
莫比乌斯反演就是在已知f的情况下反演求g
-
那么,我们可以试着用f来表示g——
g(n)=∑d|nf(d)×μ(nd) -
一脸懵逼?不知道μ函数是什么对不对?
不必知道因为这只是我们自己YY出来的觉得这里应该有的一个函数(μ就是莫比乌斯函数) -
根据上面那个表可以得知,μ函数的值域只能取{−1,0,1}
明显的同样不要问我为什么自行脑补 -
用换元法设t=nd,则
g(n)=∑d|nf(nt)×μ(t)=∑d|nf(nd)×μ(d)