UPD:2018.4.25 更新了快速求原根的啰嗦的证实html
1、整除的性质算法
1,若是a|b,且b|c,则a|c数组
2,a|b且b|c,那么a|cdom
3,设m!=0,那么a|b等价于(m*a)|(m*b)函数
4,设整数x和y知足下式,a*x+b*y=1,且a|n,b|n,那么(a*b)|n测试
根据性质3可得,(a*b)|(n*b),(a*b)|(n*a),spa
根据性质4可得,(a*b)|x*(n*a)+y*(n*b).net
化简上式,(a*b)|n*(a*x+b*y)=>(a*b)|n*(1),证毕code
5,若b=q*d+c,那么d|b的充要条件是d|cxml
其余
约定0能够被任何数整除
若2能整除a的最末位,则2|a
若4能整除a的后两位,则4|a
若8能整除a的后三位,则8|a.以此类推再也不赘述
若3能整除a的各位数字之和,则3|a
若9能整除a的各位数字之和,则9|a
若11能整除a的偶数位数字之和与奇数位数字之和的差,则11|a
同时能被7,11,13整除的数的特征是,这个数的末三位与末三位之前的数字所组成的数能被7,11,13整除,则这个数就能被7,11,13整除
显然成立容易忽略的细节?
若a|b,则a是b的一个因子,
若a|b,则a<=b
2、GCD
GCD据个人理解能够形象化的理解为,数字的最长公共子结构
因此不只仅是两个数之间的
一堆数的GCD,显然能够先从某两个数的GCD开始,由于答案一定比这个还要小
一堆定序数的GCD有一个性质那就是非严格单调递减,某一段的GCD可能不变,可是其终归是递减
这里有一个偏哲学的解释,人越多则人们的共性就越少,共性越少则最大共性也越少
GCD正确性的证实须要知道几点
若a|b则a<=b
另一个是显然但容易忽略的事实,a<=b,b<=a,显然当且仅当a=b时成立
对于a=q*d+r,q|a当且仅当q|r
展转相除法的正确性能够分红两步来证实。
在第一步,咱们会证实算法的最终结果rN−1同时整除a和b。由于它是一个公约数,因此必然小于或者等于最大公约数g。
在第二步,咱们证实g能整除rN−1。因此g必定小于或等于rN−1。两个不等式只在rN−1 = g是同时成立。具体证实以下:
由于第一步的证实告诉咱们rN−1 ≤ g,因此g = rN−1。即:
对于任意两个整数,a,b,设d是他们的最大公约数
裴蜀等式有解时必然有无穷多个解。
一般谈到最大公约数时,咱们都会提到这个很是基本的事实:给予二整数a、b,必存在有整数x、y使得ax + by = gcd(a,b)
理解要点
由于r也是A中的元素,且r>=0&&r<d0,若是r>0则说明存在比d0还小的“正”元素,这与假设矛盾
所以r只能取<=0的整数,r能够取0
理解要点2
首先咱们知道ax0+by0=d0
并且咱们知道d0能整除a,b
那么a*(x0+kb/d0)+b*(y0-ka/d0)=d0
而后咱们显然能够获得
a*(m0x0+m0kb/d0)+b*(m0y0-m0ka/d0)=m0d0
后面我好像不太会了,可是咱们知道m0x0+kb,m0y0-ka因为k是整数,因此比起上面那个形式
会漏解。。可是因为整数集是无穷数级,因此即便漏解它仍然有无穷多解(它真的会漏解吗,至少如今我看来会的)
(更新补充:
可是咱们会看到上面的证实中,标准的通解(也许叫这个名字吧)形式是,m0x0+kb/d,m0y0-ka/d
这里我又发现了一个坑。。那就是我写的是d0,可是他这里是d,个人d0就是A集合中最小的正整数,也就是gcd(a,b)
可是他这里是d...
奥我发现。。他上面说了。。这个d的意思就是a,b的任意正公约数,那么d就能整除a和b了
而且d0是最大公约数,那么d<=d0,那么b/d>=b/d0,那么对于同一个整数k,kb/d>=kb/d0
======================================================
可是这里我真正想说的是,因为(d表示任意公约数)kb/d,ka/d,最后互相乘以一个系数被约掉。。因此咱们并不关心这个系数是多少
这里t*b/d0必定能转化到k*b/d为何呢,
由于,,d=z*d0..,t*b/d0和k*b/z*d0,咱们一定有办法将1/z消去,而后规约到t的状况里。。因此我认为(t为任意整数)t*b/d0就能表明全部解
奥这下我又知道了。。由于任意正约数d的状况是包含d0的啊!MDZZ
)
那么其实咱们经过这个基本事实的证实获得了合理的解释
2、EXGCD
EXGCD实际上是基于对以上事实的观察以及对GCD迭代求解过程的观察
其实咱们知道GCD基于一个事实,假设第一个参数小于第二个参数GCD(a,b)=GCD(a,b-a)
(此处不妨设a<b,若是a>b那么GCD(b%a,a)=GCD(b,a)则仅仅至关于交换了a,b的位置)
可是咱们知道一般咱们写的GCD第一个参数老是大于第二个参数,这也是不一样于日常的另一种写法
这里有一个显然的事实a%b<b
咱们知道GCD的每一步迭代都对应着一个带余除法式子
由于咱们要知道余数是多少,由于咱们知道一旦求出了余数咱们为了保证参数顺序就要交换
继续用大数减去小数,因此GCD的全部迭代的过程都对应着带余除法式子,
这就是咱们要写一堆求余数式子的缘由,这样才能找到最大公约数和最初的参数有什么关系
数学推导能够有两种一种是从前日后,另一种是从后往前,首先咱们要写出来最基本的一堆求余数式子
(b<a)
a=q1*b+r1(r1<b)
b=q2*r1+r2(r2<r1)
r1=q3*r2+r3(r3<r2)
r2=q4*r3+r4(r4<r3)
r3=q5*r4+r5(设r5=0,r5<r4)
r4=q6*r5+r6(由于r5=0,因此r6=r4)这里返回GCD的答案r4,算法终止
那么都说那这些式子回带就能够得解
怎么回带呢,其中一种错误的回带是a-q1*b=r1
把r1回带,咱们看看有没有办法算出r1和最大公约数g的关系反解g,此处的g就是r4
(Tip:化简式子时要观察式子的结构,一个简单的想法是观察目标式子中的元素而后将多余的元素反解成目标式子中的元素)
r2=q4*(q5*r4)+r4=(1+q4*q5)*r4
r1=q3*(1+q4*q5)*r4+(q5*r4)=(q3+q3*q4*q5+q5)*r4
a-q1*b=(q3+q3*q4*q5+q5)*r4
此时咱们令a=p1*r4,b=p2*r4,由于咱们早已知道r4|a,b
p1*r4-q1*p2*r4=(q3+q3*q4*q5+q5)*r4
设存在x,y使得,x*p1*r4+y*p2*r4=r4
则r4*(x*p1+y*p2-1)=0
而式也能化解为,r4(p1*r4-q1*p2*r4-q3-q3*q4*q5-q5)=0
证实到这里咱们必需要找到(q3+q3*q4*q5+q5+1)分解成a和b的份量
因为都是商数因此,这令我感到证实困难,这种证实的主要困难是选择了a的系数固定为一,须要找到a的其余分解
这个先放在这里。。闲的时候能够强行刚一波
(b<a)gcd(a,b)
a=q1*b+r1(r1<b) gcd(b,r1)
b=q2*r1+r2(r2<r1) gcd(r1,r2)
r1=q3*r2+r3(r3<r2)gcd(r2,r3)
r2=q4*r3+r4(r4<r3)gcd(r3,r4)==>
r3=q5*r4+r5(设r5=0,r5<r4)gcd(r4,r5) r5==0 return r4 ==>1*r4+0*r5=gcd(r4,r5)=r4
r4=q6*r5+r6(由于r5=0,因此r6=r4)这里返回GCD的答案r4,算法终止
对于这堆式子。。咱们能够将r4的系数固定为1,而后从下往上迭代
首先咱们将余数所有挪到左边
r1=a-q1*b
r2=b-q1*r1
r3=r1-q3*r2
r4=r2-q4*r3
r5=r3-q5*r4
r6=r4-q6*r5
由于咱们总能迭代到r1,因此r4总能表示成(a-q1*b)的线性组合,也就是a,b的线性组合
下面开始实际证实
r4=r2-q4*(r1-q3*r2)=(1+q4*q3)r2-q4*r1(带入r3)
r4=(1+q4*q3)*(b-q1*r1)-q4*r1=(1+q4*q3)*b-r1(q1+q1*q4*q3+q4)(带入r2)
r4=(1+q4*q3)*b-(a-q1*b)(q1+q1*q4*q3+q4)(带入r1)
r4=(1+q4*q3-q1*q1-q1*q1*q4*q3-q4*q1)b-a*(q1+q1*q4*q3+q4)
r4=p1*b-p2*a=xa+yb
而后咱们也能够先把r2带入r1,依次,最后r4里面把r2和r3带入
这个证实的核心就是发现了一个事实,比r1小的余数都能表示成r1的线性组合,而比r1小的余数里面
一定有一个余数是最大公约数,最大公约数也可表示成r1的线性组合,而r1又是a,b的线性组合,因此最大公约数也是a,b的线性组合
而且咱们知道一旦知道了每一步的商和余数咱们就能算出最终最大公约数中a,b的某一个线性组合
可是咱们的程序应该怎么写呢。。
因为这是一个递归的过程,若是咱们要采用回溯迭代而不是递归生成目标多项式也就是从上往下一步带入
因此咱们要知道前一步和后一步存在什么关系,首先咱们求的是一个a,b的系数,那么咱们经过上述步骤回带,
咱们知道GCD(a,b)=GCD(b,a%b),因而咱们根据上面讲的性质之一就能够发现
存在事实,ax1+by1=bx2+(a%b)y2
在下取整乘法里咱们能够写成,ax1+by1=bx2+(a-b*a/b)y2
要想获得x1,x2,y1,y2的关系一个简单的想法,两边都整理成a*p1+b*q1=a*p2+b*q2
因此这里有一个显然可是容易忽略的事实,a*p1+b*q1=a*p2+b*q2
的一组解一定有,p1=p2,q1=q2
可是别忘了,p1!=p2,q1!=q2的状况,此时设k1,k2为整数集合中的数
则p2=p1+k1,q2=q1+k2,则a*p1+b*q1=a*(p1+k1)+b*(q1+k2)
整理可得ak1+bk2=0,咱们能够得出k1=b/d0,k2=-a/d0,若是d0|a,b
能够知道d0必定存在,由于能够取0,1等等值
根据其中一组解的思路,两边整理成一样形式的
ax1+by1=ay2+b(x2-a/b*y2)
则x1=y2,y1=(x2-a/b*y2),因此其实咱们按照这个式子回带答案就行,由于咱们知道递归的最后一步必定有解
代码实现有一点,当前x的值是x2,y的值是y2,仍然用x存x1则x=y=y2;可是y=x-a/b*y就会变成y2-a/b*y2
由于x2被覆盖,因此呢,这里须要临时变量保存x2的值
而后令我困惑的是不断迭代的这个过程其实没有用到上面推导的结论咱们只是
一味的迭代。。
当咱们想要真正模拟迭代求解的过程时
在此以前还须要强调以前的性质那就是函数定义的参数顺序,定义gcd(a,b,x,y)能够顺便求出x*a+y*b=gcd(a,b)中x,y的一组特解
因此咱们知道x对应于a,y对应于b,x,y并不知足交换的性质
这里参考上面的式子就行,假设的话,截断式子就能够
譬如设d是最大公约数,d=r3=r1-q3*r2,此时A=r1,B=r2,x1=1,y1=-q3
而后咱们将r2带入,d=r1-q3*(b-q2r1)=(-q3)*b+(1+q2q3)r1,此时A=b,B=r1,x2=-q3=y1,y2=x1-y1*b/r1(实际上b/r1就是q2)
而后其实从这里咱们就足以发现事实(其实不严谨,可是日后推导显然能够规约到这两步上面)。。那就是x2=y1,y2=x1-y1*b/r1,也就是说其实这个过程本质和上面的事实仍是同样的
因此咱们就没必要顾虑这个过程和上面的事实没有联系。。他们只是从不一样角度观察而已
因此反向带入和咱们反解系数gcd(a,b)=gcd(b,a%b)实际上是同样的啦!
用exgcd求逆元怎么求呢,求k*M=1(mod N)M<N,那么其实这个问题至关于k*M+p*N=1,而咱们知道M,N互质则有,k*M+p*N=gcd(M,N)一定有解
因此利用exgcd便可求出知足等式的一个k,(其实exgcd还知足一个性质,那就是求出来的|k|+|p|是最小的,这个用概括法容易正,由于每一步都是最小的
可是k可能会小于零,好比7,8会求得,7*-1+8=1,等式里没什么问题,可是咱们求的是逆元,那个式子还能够写成,(7*-1)%8=1,也就是说只要在等式里找到了
一个k,那么这个k一定对应一个0~N-1大小的逆元,由于和(7*-1+p*8)%8=1是等价的,p是多大并不重要,模意义下跟没有同样,
其实和,(7*(p*8-1))%8=1同样,展开可得,-7+7*p*8=1(mod 8),那么咱们可让p=7p嘛。。那么就变成了上面的(7*-1+p*8)%8=1,这样就等价了
因此因为乘法逆元的意义,他就是一个0~N-1的数,假如k<0,则咱们须要求p*8+k>0最小的数,那么咱们能够先k%8,将大于8的部分的负数都搞掉
而后k是一个在0~N-1下的负数,此时咱们再给他加上N就获得答案,可是对于正数,虽然加上N没影响,可是会大于N,因此咱们最后在模一个N
那么这个逆元就会被表示成(k%n+n)%n,正负数通用
那么还有一个理解是,何时返回答案呢,那就是,右边的大的数,被左边%成了0,那么这不就说明左边才是最终的答案嘛,返回左边
也就是if(b==0) return a;这里约定右边比左边大
为何普通线性同余方程x解的最小距离为b/gcd
每每咱们须要求解的方程并非a*x+b*y=gcd(a,b)而是更常规的a*x+b*y=n
而后能够经过对a*x+b*y=gcd(a,b)方程的求解,转化成为求二元一次不定方程a*x+b*y=n
若gcd(a,b)不能整除n,这个方程无整数解,反之,若解得a*x+b*y=gcd(a,b)的解为x0,y0,
则方程两边同乘n再除以gcd(a,b)得a*(n/gcd(a,b)*x0)+b*(n/gcd(a,b)*y0)=n
因此方程解为x=n/gcd(a,b)*x0,y=n/gcd(a,b)*y0。
更一般的是:咱们须要求解方程的最小整数解
若咱们已经求得x0,y0为方程中x的一组特解,那么
x=x0+b/gcd(a,b)*t,y=y0-a/gcd(a,b)*t(t为任意整数)也为方程的解
且b/gcd(a,b),a/gcd(a,b)分别为x,y的解的最小间距,因此x在0~b/gcd(a,b)区间有且仅有一个解,
同理y在0~a/gcd(a,b)一样有且仅有一个解,这个解即为咱们所需求的最小正整数解。
为何b/gcd(a,b),a/gcd(a,b)分别为x,y的解的最小间距?
解:假设c为x的解的最小间距,此时d为y的解的间距,因此x=x0+c*t,y=y0-d*t(x0,y0为一组特解,t为任意整数)
带入方程得:a*x0+a*c*t+b*y0-b*d*t=n,由于a*x0+b*y0=n,因此a*c*t-b*d*t=0,t不等于0时,a*c=b*d
由于a,b,c,d都为正整数,因此用最小的c,d,使得等式成立,ac,bd就应该等于a,b的最小公倍数a*b/gcd(a,b),
因此c=b/gcd(a,b),d就等于a/gcd(a,b)。
因此,若最后所求解要求x为最小整数,那么x=(x0%(b/gcd(a,b))+b/gcd(a,b))%(b/gcd(a,b))即为x的最小整数解。
x0%(b/gcd(a,b))使解落到区间-b/gcd(a,b)~b/gcd(a,b),再加上b/gcd(a,b)使解在区间0~2*b/gcd(a,b),
再模上b/gcd(a,b),则获得最小整数解(注意b/gcd(a,b)为解的最小距离,重要)
摘自:http://blog.csdn.net/non_cease/article/details/7364092
3、同余理论
若a,b为两个整数,且它们的差a-b能被某个天然数m所整除,则称a就模m来讲同余于b,或者说a和b关于模m同余
记为a=b(mod m)(同余符号懒得弄了,暂时就拿等号代替)
它意味着,a-b=m*k(k为某一个整数),例如32=2(mod5) k=6
还有一种理解同余的说法,那就是两个数把多余的部分(大于模数的部分)砍掉,剩下的数值同样,那么咱们就说这两个数同余
对于整数a,b,c和天然数m,n, 对模m同余具备如下一些性质
1,自反性,a=a(mod m)
2,对称性,若a=b(mod m) 则 b=a(mod m)
3,传递性,若a=b(mod m),b=c(mod m),则a=c(mod m)
4,同加性,若a=b(mod m),则a+c=b+c(mod m)
5,同乘性,若a=b(mod m),则a*c=b*c(mod m)
若a=b(mod m) c=d(mod m) 则 a*c=b*d(mod m)
6,同幂性,若a=b(mod m),则an=bn(mod m)
7,推论1,a*b mod k=(a mod k)*(b mod k) mod k
8,推论2,若a mod p=x, a mod q=x,p、q互质,则a mod p*q=x
证实,p,q互质则必定 存在整数s,t使得 a=sp+x,a=tq+x
那么显然咱们能够获得,sp=tq,由于p,q互质,因此必定存在s=kq
因此a=(kq)p+x=kqp+x,所以 a=x(mod p*q)
可是同余不知足同除性,即不知足a div n = b div n (mod m)
咱们知道若是div n是逆元的话,设L=inv(n,m),则a*L=b*L(mod m)是知足同乘性质
可是此处却说不知足,可见并非逆元乘法当除法?
因此这里是一个有疑惑的地方
关于同余这里有一个快速的指数取余的算法
那就是快速幂,快速幂基于两个事实,咱们能够在log的时间把一个数分解成2进制
ab=ab0*ab1....*abn,而后咱们知道b0到bn的和就是b,可是咱们没必要求出具体数值
例如11011=1+10+1000+1000,咱们能在对数时间内求得,a,a*a,a*a*a*a,咱们知道
对于二进制的偶数次幂,咱们能够直接利用结果,奇数次幂能够用a*偶数次幂,也就是基于偶数加一等于奇数这一基本事实
因此咱们能够组装成任意的幂次,注意特判b=0的状况
求解线性同余方程
定理1:对于方程a*x+b*y=c,该方程等价于a*x=c(mod b),有整数解的充分必要条件是:c%GCD(a,b)=0
根据定理1,对于方程a*x+b*y=c,咱们能够先用扩展欧几里得算法(EXGCD)求出一组x0,y0,
也就是ax0+by0=GCD(a,b),而后两边同时除以GCD(a,b),再乘以c
这样就获得了,a/GCD(a,b)*c*x0+b/GCD(a,b)*c*y0=c,咱们也就找到了方程的一个解
定理2:若GCD(a,b)=1,且x0,y0为a*x+b*y=c的一组解,
则该方程的任一解可表示为,x=x0+b*t,y=y0-at
这里有一个显然但容易忽略的事实,GCD(a/GCD(a,b),b/GCD(a,b))=1,即两个数都除以GCD,则运算后的结果互质
并且咱们也能够这么想,ax0+by0=GCD(a,b),同除以GCD(a,b),a/GCD(a,b)*x0+b/GCD(a,b)*y0=1,
咱们知道它的解必定存在,那么根据上述的某一条性质咱们能够得出结论,a/GCD(a,b)与b/GCD(a,b)互质
而且咱们知道GCD(a,b),的含义在这里是可以整除a,b的最大约数,若是约数比GCD(a,b)还大,那么a,b至少有一方不能被此约数整除
因此根据定理2,考虑方程a*x+b*y=c=>a/GCD(a,b)*x+b/GCD(a,b)*y=c/GCD(a,b)
因而咱们能够获得方程,A*x+B*y=C,GCD(A,B)=1,因而咱们能够获得(x0,y0是ax+by=c的一组解)
x=x0+B*k,y=y0-A*k,(A=a/GCD(a,b),B=b/GCD(a,b)),因此这里咱们就求得了a*x+b*y=c的全部解
咱们在求出特解x0,y0时,向全部解推广时,运用了上面一个显然的事实
a*(-b)-b*(a)=0,那么咱们知道当你得到了ax0+by0=c,你能够写成a(x0+bk)+b(y0-ak)=c
可是这里k取整数则会漏解,由于咱们知道要想这个式子成立,x0须要加上一个b为分子,能整除a,b的的数做为分母
y0须要减去一个a为分子,能整除a,b的数做为分母,(这两个分母固然取同样的)这样才能知足等式
可是咱们知道能整除a,b的数很是多,but 咱们知道了能同时整除a,b最大的数,咱们取这个数做分母
k取任意整数就能得到全部解,你担忧漏掉a,b其余公共约数做为分母的状况的解?不存在的,由于k是任意的
k能枚举全部其余公约数为分母比(例如b/GCD(a,b))大的部分的全部因子的状况,因此这有点相似于基元的思想
因此咱们来推一下这个解最终的形式应该是怎么样的,要求ax+by=c的解
咱们只能先求出ax+by=GCD(a,b)的解,设这组解为x0,y0
给这组解同乘以c/GCD(a,b),这样咱们就获得了ax+by的一组解,X0=x0*c/GCD(a,b),Y0=y0*c/GCD(a,b)
而后咱们知道通解X=X0+B*k,Y=Y0-A*k,带入X0,Y0,A,B,(A=a/GCD(a,b),B=b/GCD(a,b))
X=x0*c/GCD(a,b)+b/GCD(a,b)*k,Y=y0*c/GCD(a,b)-a/GCD(a,b)*k,其中k能够取任意整数
但在实际问题中,咱们每每被要求去求最小整数解,也就是一个特解,
X=(X%B+B)%B,Y=(Y%A+A)%A,
因此就是X1=(X0%B+B)%B, Y1=(Y0%A+A)%A
那么为何这样就能求出最小整数解呢
由于全部解的形式后面都带B*k,或者A*k,咱们把这些都%掉
就剩下最小的X0,Y0,而后咱们知道%剩下的这些必定小于B或A(取模运算)
那么若是此时(c语言%运算)%的结果小于零,可是它的绝对值的结果必定小于B或A
此时咱们再给他加上B或A,因此咱们求出的是最小非负整数解
由于这个解有多是零
逆元
若a*x=1(mod b) ,a,b互质,则称x为a的逆元,记为a-1
根据逆元的定义,可转化为a*x+b*y=1,咱们知道若是a,b互质,那么GCD(a,b)=1
那么咱们只需跑一趟EXGCD就能算出来a的逆元是多少
求逆元还有一个线性算法,具体过程以下
首先1-1=1(mod p)
而后咱们设p=k*i+r,是p/i的带余除法,令i>1&&i<p,令p是质数,那么全部i都与p互质,都互质那么就都存在逆元
而后咱们显然能够知道r<i,这意味着r也是存在逆元的,再将这个式子放到mod p的意义下
k*i+r=0(mod p)
在两边同时乘上i-1,r-1就会获得
k*r-1+i-1=0(mod p)
i-1=-k*r-1(mod p)
i-1=-(p/i)*(p%i)-1(mod p)
由于咱们不想得出一个小于零的结果,咱们知道
p-(p/i)=p/i(mod p) 因此做替换
i-1=(p-(p/i))*(p%i)-1(mod p)
这就是线性求逆元的递推式子了
实际上这也提供了一种O(logn)底数为2,
的时间内求出单个数逆元的方法,只要直接按照那个公式递归就能够了。能够证实p mod i<i/2
每次递归问题规模减半,最终只会有O(logn)次递归,GCD貌似只须要位数乘5的复杂度,这个要比GCD快一个常数
我忽然想到了GCD和线性差分方程,然而线性差分方程又和斐波那契数列有关(斐波那契数列是线性差分方程的一种特殊形式)
GCD为何和线性差分方程有关呢
好比说这种形式
r1=a-q1*b
r2=b-q1*r1
r3=r1-q3*r2
r4=r2-q4*r3
r5=r3-q5*r4
r6=r4-q6*r5
这不就是典型的差分形式么
整数的惟一分解定理
任意正整数都有且只有一种方式写出其素因子的乘积表达式
A=(p1^k1)*(p2^k2)*(p3^k3)....*(pn^kn),其中pi为素数
这里有一个显然可是容易忽略的事实
那就是A和A/(pi^ki)互质
约数和公式
对于已经分解的整数,A=(p1^k1)*(p2^k2)*(p3^k3)....*(pn^kn)
有A的全部因子之和为
S=(1+p1^1+p1^2+...+p1^k1)*(1+p2^1+p2^2+...p2^k2)*(1+p3^1+p3^2+...+p3^k3)*...(1+pn^1+pn^2+...pn^kn)
这个很好理解,由于A的全部因数必然是A中全部素因子及其幂次的组合(与顺序无关全部和排列没有关系)
同余模公式
(a+b)%m=(a%m+b%m)%m
(a*b)%m=(a%m+b%m)%m
这个很是好理解,由于若是a=km+r,则你先%m对答案无影响
若是k=0,也是没有影响的
素因子分解
不断对A的素因子取模,只要A%pi==0,则cnt[pi]++,A/=pi,当A%pi!=0时咱们分解pi+1
可是咱们须要对A自己就是一个素数进行特判
求A^B的全部约数之和
sum=(1+p1^1+p1^2+...+p1^(k1*B))*(1+p2^1+p2^2+...+p2^(k2*B))*...*(1+pn^1+pn^2+...+pn(kn*B))
对于每个pi咱们须要
递归二分求等比数列1+pi+pi^2+...+pi^n
本质就是咱们提出来一个因子使得问题的规模缩小一半
n分奇偶来讨论,若是n是奇数则一共有偶数项好比说n=7
下取整除法
pi^0 pi^4
pi^1 pi^5
pi^2 pi^6
pi^3 pi^7
因此咱们就发现了pi^(7/2+1)+...+pi^7=(1+pi^1+...+pi^(7/2))*(pi^(7/2+1))
而后1+pi^1+pi^2+...+pi^7=(1+pi^1+...+pi^(7/2))+(1+pi^1+...+pi^(7/2))*(pi^(7/2+1))=(1+pi^1+...+pi^(7/2))*(1+pi^(7/2+1))
其实咱们发现若是n是奇数。。则都是知足这个规律的
若是n是偶数,好比说n=8
pi^0 pi^5
pi^1 pi^6
pi^2 pi^7
pi^3 pi^8
可是咱们发现少了pi^4,因此偶数状况的形式应该是(1+pi^1+pi^2+...+pi^(n/2-1))*(1+pi^(n/2+1))+pi^(n/2)
奇数状况的形式应该是(1+pi^1+pi^2+...+pi^(n/2))*(1+pi^(n/2+1))
因此这样咱们就能递归求解等比数列和了
中国剩余定理 CRT
设天然数m1,m2,...,mr两两互素,并记N=m1*m2*...*mr,则同余方程组
x=b1(mod m1)
x=b2(mod m2)
...
x=br(mod mr)
在模N同余的意义下有惟一解
仅仅是这个结论,它并不显然,可是只要咱们能构造出解,就证实了这个结论
证实:
考虑方程组
(i>=1&&i<=r)
x=0 (mod m1)
...
x=0(mod mi-1)
x=1(mod mi)
x=0(mod mi+1)
...
...
x=0(mod mr)
因为诸mi两两互素,这个方程组做变量替换,令x=(N/mi)*y
方程组等价于解同余方程,(N/mi)*yi=1(mod mi),咱们知道GCD(N/mi,mi)=1
因此yi必定有解,则xi=(N/mi)yi
则方程组的解为X=x1*b1+x2*b2+...+xr*br(mod N)
答案超过N怎么办。。咱们边算边模就好了
斐波那契数列,常系数差分方程,待定系数法求通解
因此最终答案就是s^n(f1-rf0)+r^n(sf0-f1)/(s-r)
这是这种方程的通解,而后对于项数很大的常系数差分方程,咱们能够利用矩阵快速幂
[F(n-1),F(n-2)]*(a 1)=[a*F(n-1)+b*F(n-2),F(n-1)]=[F(n),F(n-1)]
(b 0)
而后依次类推就好了,就能一直算出后面的项
卡特兰数
求卡特兰数列的第n项,能够用以下几个公式
1.递归公式1
2.递归公式2
3.组合公式1
4.组合公式2
素数理论
素数的断定
在数据范围比较小的状况下,咱们能够sqrt(N)判断一个数是否是素数,若是数据规模是S则总共须要S*sqrt(S)才能判别全部数,很是慢
它的原理就是考虑全部<=sqrt(N)的N的约数,为何不考虑>sqrt(N)的约数?由于若是一个约数大于sqrt(N)那么另一个约数一定小于sqrt(N)
对于数据范围较大的状况,咱们须要素数筛法
一个经典的素数筛法是这样的,
先将2~N(1不是素数不考虑)之间全部数写在纸上,
在2的上面画圈,而后划去2的其余倍数,第一个既没有画圈也没被划去的数是3
在3的上面画圈,而后划去3的其余倍数
重复上面这个过程,知道<=N的全部数都被考虑过画圈仍是被划去
i是过程当中第一个既没有画圈也没被划去的数
其中咱们在枚举i的倍数时,只需从i*i开始筛,由于k*i(k<i)的状况已经被考虑过
从上述算法咱们能够发现事实
该算法会形成重复筛除合数,
30=2*15=5*6 因此说30会被重复筛除
因此这里有了一个线性的筛法
首先,明确一个条件,任何合数都能表示成一系列素数的乘积
考虑i是不是质数
1.若是i是素数的话,那简单,一个大的素数i乘以不大于i的素数,这样筛除的数跟以前的是不会重复的
2.若是i是合数,此时i能够表示成递增素数相乘i=p1*p2*p3*...*pn,pi都是素数
(i>=2&&i<=n),pi<=pj(i<=j),p1是最小的系数
这种筛法的关键就在于,当咱们判断p1==prime[j]的时候,再也不进行筛除,开始下一轮
何时判断p1==prime[j]呢,因为prime数组单调递增(从小往大筛除顺序决定的)
因此当i第一次碰到,i%prime[j]==0,就说明了p1==prime[j],由于prime[j]是i最小的质因数
能够直观地举个例子,当i=2*3*5,咱们能够筛去2*i,可是没有必要筛除3*i
若是i'=3*3*5,因为i'%2!=0,因此2*i'必定被筛去,可是3*i==2*i',便可以表示成一个更大的合数和一个更小的质数的乘积
这个终止条件咱们还能够这么看待,i%prime[j]==0
i=k*prime[j]
此时不终止算法咱们将筛,i*prime[j+1],而prime[j+1]>prime[j]
i*prime[j+1]=k*prime[j]*prime[j+1]=(乘法交换律)k*prime[j+1]*prime[j]
咱们看到k*prime[j+1]是比i大的合数,prime[j]是比prime[j+1]小的质数
因此仍然是避免了下一个筛除的数能够表示成一个更大的合数和更小的质数的乘积
并且咱们知道这个算法的核心就在于
每一个数咱们只用他最小的质因子去筛除
还有两个结论能够证实
1.一个数不会被重复筛除
2.合数确定会被筛除
为何一个数不会被重复筛除呢。。仍是基于前面对数字的惟一表示法的限定
我说的这个惟一表示法是什么呢,就是咱们知道一个数能够被分解成惟一素因子的幂次的乘积的形式
可是若是这么多散开的因子(2^3散开就是2*2*2),不按照固定的规则排列,那么显然有n!的排列方式(这里只是粗略地算了一下,实际应该是可重集合排列
因此这样不行,咱们把它全部素因子所有排序。。那么他就能够表示成i*a,i是它最小的素因子,a固然不用管啦,咱们把它内部当作有序的不就行了吗
固然a的最小素因子是大于等于i的,
因此在筛2*3*5时,为何不筛素因子3,5呢,筛3的话会筛掉3*2*3*5,然而这和排序后的2*3*3*5是等价的,素数2能够轻易处理这种状况
筛5呢,5*2*3*5,然而和排序后的2*3*5*5等价,3*5*5遍历2时便可处理,当前处理则是不明知的重复劳动
内循环有一个细节,i*pr[j]<maxn,若是没有这个。。不只会多跑。。并且可能会越界re
假设合数不能被筛除,则说明合数不能表示成最小质数i*a(最小质数大于等于i的数),这显然是不成立的。。可是我感到这是不严谨的,,后续再补
素数的相关定理
1.惟一分解定理
2.威尔逊定理
若p为素数,则(p-1)!=-1(mod p)(!是阶乘符号)
威尔逊定理的逆定理也成立
3.费马定理
若p为素数,a为正整数,且,a和p互质,则a^(p-1)=1(mod p)
证实:
首先,p-1个整数,a,2a,3a,...,(p-1)a 中没有一个是p的倍数(a与p互质)
其次,a,2a,3a,...,(p-1)a中没有任何两个同余于mod p
由于a=1(mod p) a*i=i(mod p) (i>=1&&i<p)(这个是错的)
由于没有任何一个数能表示成 ka=qp+r,其中q>=1
q只能等于0,因此每一个(等会这个也是错的)
假设存在s1,s2(均小于等于p-1)使得,a*s1=a*s2(mod p),且s1!=s2,a与p互质
两边同乘以a的逆元能够获得
s1=s2(mod p),可是s1,s2都<=p-1&&>=1,s1必定等于s2,这与假设矛盾,所以不存在s1,s2
也就不存在
因而:a,2a,3a,...,(p-1)a,对mod p的同余既不为0,也没有两个同余相同,
因为s*a!=s(mod p),因此咱们只有算一下才知道是多少
而且mod p的结果有p个0~p-1,可是没有0,因此就剩下p-1个,然而这p-1个结果还各不相同,
因此说这p-1个数对模p的同余结果必定是,1,2,3,...,p-1的某种排列
也就是,a*2a*3a*...*(p-1)a=1*2*3*...*(p-1)(mod p)
化简能够获得,a^(p-1)*(p-1)!=(p-1)!(mod p)
因为(p-1)!和p显然互质,因此(p-1)!的逆元必定存在
因此咱们两边同时乘以(p-1)!的逆元,式子就变成了a^(p-1)=1(mod p)
其实这是一种特殊状况,通常状况下,若p为素数,则a^p=a(mod p)
这就是著名的费马小定理
Miller-Rabin素数测试
说Miller-Rabin测试之前先说两个比较高效的求a*b% n 和 ab %n 的函数,这里都是用到二进制思想,将b拆分红二进制,而后与a相加(相乘)
下面这个方法还有另一个名字,俄罗斯乘法(雾)
// a * b % n
//例如: b = 1011101那么a * b mod n = (a * 1000000 mod n + a * 10000 mod n + a * 1000 mod n + a * 100 mod n + a * 1 mod n) mod n
ll mod_mul(ll a, ll b, ll n) {
ll res = 0;
while(b) {
if(b&1) res = (res + a) % n;
a = (a + a) % n;
b >>= 1;
}
return res;
}
当相乘的两个数在long long 范围内的时候咱们可使用O(1)乘法
inline LL Multiply(LL x, LL y) { LL w = x * y - (LL)((double)x * y / p + 0.001) * p; if(w < 0) w += p; return w; }
//a^b % n
//同理
ll mod_exp(ll a, ll b, ll n) {
ll res = 1;
while(b) {
if(b&1) res = mod_mul(res, a, n);
a = mod_mul(a, a, n);
b >>= 1;
}
return res;
}
下面开始说Miller-Rabin测试:
费马小定理:对于素数p和任意整数a,有ap ≡ a(mod p)(同余)。反过来,知足ap ≡ a(mod p),p也几乎必定是素数。
伪素数:若是n是一个正整数,若是存在和n互素的正整数a知足 an-1 ≡ 1(mod n),咱们说n是基于a的伪素数。若是一个数是伪素数,那么它几乎确定是素数。
Miller-Rabin测试:不断选取不超过n-1的基b(s次),计算是否每次都有bn-1 ≡ 1(mod n),若每次都成立则n是素数,不然为合数。
伪代码:
Function Miller-Rabin (n : longint) :boolean;
begin
for i := 1 to s do
begin
a := random(n - 2) + 2;
if mod_exp(a, n-1, n) <> 1 then return false;
end;
return true;
end;
注意,MIller-Rabin测试是几率型的,不是肯定型的,不过因为屡次运行后出错的几率很是小,因此实际应用仍是可行的。(一次Miller-Rabin测试其成功的几率为3/4)
前边说的伪代码实现很简短,下面还有一个定理,能提升Miller测试的效率:
二次探测定理:
若是p是奇素数,则 x2 ≡ 1(mod p)的解为 x = 1 || x = p - 1(mod p);
能够利用二次探测定理在实现Miller-Rabin上添加一些细节,具体实现以下:
bool miller_rabin(ll n) {
if(n == 2 || n == 3 || n == 5 || n == 7 || n == 11) return true;
if(n == 1 || !(n%2) || !(n%3) || !(n%5) || !(n%7) || !(n%11)) return false;
ll x, pre, u;
int i, j, k = 0;
u = n - 1; //要求x^u % n
while(!(u&1)) { //若是u为偶数则u右移,用k记录移位数
k++; u >>= 1;
}
srand((ll)time(0));
for(i = 0; i < S; ++i) { //进行S次测试
x = rand()%(n-2) + 2; //在[2, n)中取随机数
if((x%n) == 0) continue;
x = mod_exp(x, u, n); //先计算(x^u) % n,
pre = x;
for(j = 0; j < k; ++j) { //把移位减掉的量补上,并在这地方加上二次探测
x = mod_mul(x, x, n);
if(x == 1 && pre != 1 && pre != n-1) return false; //二次探测定理,这里若是x = 1则pre 必须等于 1,或则 n-1不然能够判断不是素数
pre = x;
}
if(x != 1) return false; //费马小定理
}
return true;
}
前边这个算法通过测试仍是比较靠谱的,能够用做模板。本菜也找过其余模板,但是有的竟然把9测成素数,汗 -_-!
额,这个是我转的
尊重做者:AC_Von 原创,转载请注明出处:http://www.cnblogs.com/vongang/archive/2012/03/15/2398626.html
Miller-Rabin理解的时候有一个我本身的小trick
n%(n-2)的范围是0~n-3,而不是0~n-1,这一点千万别搞错!
而后0~n-3,加上2,就变成了2~n-1,make sense
欧拉定理
费马定理是用来阐述在素数模下,指数的同余性质。当模式合数的时候,就要应用范围更广的欧拉定理
欧拉函数:对正整数n,欧拉函数是小于等于n的数中与n互质的数的数目
欧拉函数又称为phi函数,例如phi(8)=4,由于1,3,5,7与8互质
引理1:
1.若是n为某一个素数p,则phi(p)=p-1
2.若是n为某一个素数p的幂次p^a,则phi(p^a)=(p-1)*p^(a-1)
3.若是n为任意两个互质的数a,b的乘积,则phi(a*b)=phi(a)*phi(b)
证实:
1.显然
2.由于比p^a小的正整数一共有p^(a)-1个
其中,全部能被p整除的数,均可以表示成p*t(t=1,2,3,...,p^(a-1)-1),若是t=p^(a-1)-1+1=p^(a-1)
则pt=p^a,不知足比p^a小的条件,因此t只能到p^(a-1)-1
也就是说一共有p^(a-1)-1个数能被p整除,从而不与p^a互质
因此phi(p^a)=(p^(a)-1)-(p^(a-1)-1)=p^a-p^(a-1)=(p-1)*(p^(a-1))
3.在比a*b小的a*b-1个整数中,只有那些既和a互质(phi(a)个),又和b互质(phi(b) 个)
的数才会与a*b互质,显然知足这种条件的数有phi(a)*phi(b)个,因此有phi(a*b)=phi(a)*phi(b)
引理2:
设n=p1^a1+p2^a2+p3^a3+...+pk^ak
为正整数n的素数幂乘积表达式
则phi(n)=n*(1-1/p1)*(1-1/p2)*...*(1-1/pk)
证实:因为诸素数幂之间是互质的,根据引理1得出:
phi(n)=phi(p1^a1)*phi(p2^a2)*...*phi(pk^ak)
=p1^a1*(1-1/p1)*p2^a2*(1-1/p2)*...*pk^ak*(1-1/pk)
=p1^a1*p2^a2*...*pk^ak*(1-1/p1)*(1-1/p2)*...*(1-1/pk)
好比phi(100)=phi(2^2*5^2)=100*(1-1/2)*(1-1/5)=100*2/5=40
欧拉定理
若a与m互质,则a^(phi(m))=1(mod m)
Pollard Rho算法求大数因子
首先,对于任意一个偶数,咱们均可以提取出一个2的质因子,若是结果仍然为偶数,则可继续该操做
直至其化为一个奇数和2的多少次幂的乘积,
那么咱们能够假定这个奇数能够被表示为N=2*n+1,若是这个数是合数,那么必定能够写成N=c*d的形式
不难发现式子中的c,d都是奇数,不然N是偶数,不妨设c<d,c=d怎么办,c=d咱们则能够写成c=1,d=N=c*d,这样就行了
咱们能够令a=(c+d)/2,b=(c-d)/2
那么咱们能够获得,a*a=c^2+d^2+2cd/4,b*b=c^2+d^2-2cd
a*a-b*b=4cd/4=cd=N
则N=a*a-b*b
这正是Fermat整数分解的基础
由基本不等式可得 a>=sqrt(c*d)=sqrt(N)
那么咱们就枚举大于N的彻底平方数a*a
计算a*a-N的值,判断计算的结果是不是一个彻底平方数,若是是的话,则a+b和a-b都是N的因子(由于N=a^2-b^2=(a+b)*(a-b)=c*d)
而后咱们就能够将算法递归地进行下去,直到求出n的全部质因子
pollard-rho。是一个寻找n的因子的方法。基于这个事实:若是a不为n的倍数,那么gcd(a,n)为n的一个因子。
I、选取一个x1
II、利用函数计算出x2使得x2-x1不被n整除。
III、若是gcd(x2-x1,n)>1那么找到因子,结束过程
IV、不然重复I。
因此这里这个显然可是容易忽略的事实,若是a不为n的倍数,那么gcd(a,n)为n的一个因子。派上大用场了。。
具体操做当中,咱们一般使用函数 x[i+1]=(x[i]*x[i]+c)mod n 来计算逐步迭代计算a和b的值
实践中一般取c=1,即b=a*a+1,在下一次计算中,将b的值赋给a,
再次使用上式来计算新的b值,当a,b出现循环时,便可退出进行判断,固然初值由本身肯定,
可是这样的话判断循环比较麻烦,咱们能够用另外一种方法。
是由Floyd发明的一个算法,咱们举例来讲明这个聪明又有趣的算法
假设咱们在一个很长很长的圆形轨道上行走,咱们如何知道咱们已经走了一圈呢,固然咱们能够像第一种方法那样作
更聪明的方法是让A和B按照B的速度是A的两倍从同一块儿点开始往前走,当B第一次遇上A时,(套圈,由于B在第一圈以内必定没法和A相遇除非速度同样)
咱们便知道B已经走了至少一圈。
因此咱们能够把x看成B,y看成A来进行循环测试,具体实现详见参考程序
先来讲一下欧拉函数的线性筛法
咱们要证实的是其中要用到的一个结论,
若是i mod p==0,那么phi(i*p)=p*phi(i)
========================
设P是素数,
若p是x的约数,则E(x*p)=E(x)*p.
若p不是x的约数,则E(x*p)=E(x)*E(p)=E(x)*(p-1).
证实以下:
E(x)表示比x小的且与x互质的正整数的个数。
*若p是素数,E(p)=p-1。
*E(p^k)=p^k-p^(k-1)=(p-1)*P^(k-1)
证:令n=p^k,小于n的正整数数共有n-1即(p^k-1)个,其中与p不质的数共[p^(k-1)-1]个(分别为1*p,2*p,3*p...p(p^(k-1)-1))。
因此E(p^k)=(p^k-1)-(p^(k-1)-1)=p^k-p^(k-1).得证。
*若ab互质,则E(a*b)=E(a)*E(b),欧拉函数是积性函数.
*对任意数n均可以惟一分解成n=p1^a1*p2^a2*p3^a3*...*pn^an(pi为素数).
则E(n)=E(p1^a1)*E(p2^a2)*E(p3^a3)*...*E(pn^an)
=(p1-1)*p1^(a1-1)*(p2-1)*p2^(a2-1)*...*(pn-1)*pn^(an-1)
=(p1^a1*p2^a2*p3^a3*...*pn^an)*[(p1-1)*(p2-1)*(p3-1)*...*(pn-1)]/(p1*p2*p3*...*pn)
=n*(1-1/p1)*(1-1/p2)*...*(1-1/pn)
* E(p^k) =(p-1)*p^(k-1)=(p-1)*p^(k-2)*p
E(p^(k-1))=(p-1)*p^(k-2)
->当k>1时,E(p^k)=E(p*p^(k-1))=E(p^(k-1))*p.
(当k=1时,E(p)=p-1.)
由上式: 设P是素数,
若p是x的约数,则E(x*p)=E(x)*p.
若p不是x的约数,则E(x*p)=E(x)*E(p)=E(x)*(p-1). 证实结束。
咱们能够取证实过程当中的一个结论。。那就是E(p^k)=E(p^(k-1))*p,实际上这是一个显然但容易忽略的事实
为何显然呢,咱们知道E(p^k)=(p^k-1)-(p^(k-1)-1)=p^k-p^(k-1)=p*p^(k-1)-p^(k-1)=(p-1)*p^(k-1)
咱们只需提取一个p,变成(p-1)*p^(k-2)*p,显然,E(p^(k-1))=(p-1)*p^(k-2),那么就能够写成E(p^(k-1))*p,
前提是k>1,
而后若是i mod p==0,那么i不断对p取模,直到i%p!=0,i能够写成i=q*p^r
则E(i*p)=E(q*p^r*p)=E(q*p^(r+1)),咱们知道q和p^r互质(显然),那么固然q和p^(r+1)也互质
因此E(q*p^(r+1))=E(q)*E(p^(r+1)),运用截取的事实
E(q)*E(p^(r+1))=E(q)*E(p^r)*p,然而E(i)=E(q)*E(p^r)
因此E(q)*E(p^r)*p=E(i)*p,
则结论,E(i*p)=E(i)*p成立,证毕
这里咱们考虑了在线性筛中i%pr[j]==0的状况,互质的状况呢
显然若是没有碰到i%pr[j]==0的状况时,这个合数(质数就不用考虑了),尚未遇到和他最小的质因子相等的质数,那么又惟一分解定理可知,这些状况
两个数都是互质的
BabyStep-GiantStep 及扩展算法
有一个显然可是容易忽略的事实,A>0,A若是不是C的倍数,A必定小于C,(若是C是质数那么A和C必定互质)
先来了解一个概念:离散对数,离散对数是一种在整数中基于同余运算和原根的对数运算。
原根就是。。
并非每个模都存在原根。。
当模m有原根时,设G为模m时的一个原根,则当x=G^k(mod m)时,logG(x)=k(mod phi(m))由于G^(phi(m))=1,因此多于phi(m)的部分砍掉就行了,
Baby-Step Giant-Step 及 扩展算法 Extended BSGS
用来求解A^(x)=B(mod C)
(x>=0&&x<C)这样的问题,
由于C是质数,若是A是C的倍数则B=0,不然A<C,则A,C互质
则A的幂次mod C有循环节(欧拉定理),因此x是这个范围的
这个算法是以空间换时间,对穷举算法的一个改进
原始的BSGS只能解决C为素数的状况
设m=sqrt(C)上取整,x=i*m+j,那么A^x=(A^m)^i*A^j(i>=0&&i<m,j>=0&&j<m)
若是咱们枚举i,j则这是sqrt(C)*sqrt(C)的,可是这样咱们就枚举出了全部的x,由此可知该枚举方法的正确性
其实就是。。咱们须要枚举小于sqrt(C)和大于sqrt(C)的状况
可是咱们能够只枚举i,这是sqrt(C)级别的枚举
对于一个枚举出来的i,令D=(A^(m)^i),如今问题转化为了求D*A^j=B(mod C)
因为A,C互质,则A的幂次也和C互质,因此至关于求Dx+Cy=B
而GCD(D,C)=1,因此B%(GCD(D,C))==0,因此x必定有解,即A^j必定有解
因此跑一遍扩展欧几里得算法,咱们就能算出A^j是多少
求出了A^j,如今的问题就是我怎么知道j是多少,一个很是聪明的方法是,先用sqrt(C)的时间
将A^j所有存进hash表里面,而后查表只需O(1)就知道j是多少了,固然这里是手工Hash的复杂度
若是你用map的话,大概是O(log(sqrt(C)))
消因子
关于消因子,是这样的,
A=B(mod m)
那么咱们能够推出 A=B(mod mc)
而后咱们又能够推出
AC=BC(mod mc)
那么因为是充分必要条件,咱们也能够反推回A=B(mod m)
咱们也能够这么想,A=B(mod m)
能够看做是A=pm+r,B=qm+r,同余嘛,r相同
那么咱们能够推出,AC=pCm+Cr,BC=qCm+Cr
这个能够推出AC=BC(mod mC)
那么若是AC,和mC有公因子,这个状况显然有公因子C嘛,因而咱们能够消去公因子,那么BC也要消去一样的公因子C
那么能够推出,A=B(mod m)
扩展的BSGS不要求C是素数,大体的作法和原始的BSGS同样
只是作一些修改,由于同余具备一条性质
令d=GCD(A,C),A=a*d,B=b*d,C=c*d
则a*d=b*d(mod c*d)
等价于a=b(mod c)
所以开始前先消除因子
只要GCD(A,C)!=1,咱们就A,B,C都同除以GCD(A,C)
其中A不用真的除,咱们记录一个D=1,每次D*=A/GCD(A,C),和乘法的次数cnt
在消除因子时若是GCD(A,C)!=1,且B%(GCD(A,C))!=0此时无解
为何呢
假设a*d=k(mod c*d)
则a*d=q*c*d+k
显然d能整除a*d,那么d也能整除k,若是d不能整除k就无解
进一步分析咱们能够知道假如A是小于d的,那么K<d,(mod Cd)
假如A是d的倍数,那么mod C*d是绝对不会剩下一个比d还小的数,
而且这个数必定是d的倍数,刨去单个的d,同理不会剩下比d小的数,因此必定是d的倍数,因此必定会被d整除
前提是A是d的倍数哦
执行完上面的过程,问题变成了,D*A^(x-cnt)=B(mod C)
令x=i*m+j+cnt
后面作法就跟BSGS同样了。
可是注意到i>=0,j>=0,咱们明显存在小于等于cnt的状况,
因此在消因子以前须要作一次log(C)的枚举,直接验证A^i%C=B
听说这样是要考虑到ρ型轨道,问题来了,,轨道是什么呢
那个轨道是这样,由于n^x mod p 的值最终会产生循环,因此你能够想象各类轨道就好像循环的链表!
阶:知足 x r ≡ 1 (mod m) 最小正整数 r 称为 x 的阶 ordm(x) ,不可贵到 ordm(x) | ϕ(m)
由于phi(m)是循环节结尾,若是有比phi(m)小的循环节尾,那么那个数必定能够整除phi(m)
断定a是否为x的原根
枚举 phi(x) 的因子,熟知阶是 phi(x) 的因子,
可是你发现若是某个 a^(phi(x)/(prime factor of phi(x))) 是 1
从2开始枚举,而后暴力判断g^(P-1) = 1 (mod P)是否当且当指数为P-1的时候成立
例如求任何一个质数x的任何一个原根,通常就是枚举2到x-1,并检验。有一个方便的方法就是,求出x-1全部不一样的质因子p1,p2...pm,对于任何2<=a<=x-1,断定a是否为x的原根,只须要检验a^((x-1)/p1),a^((x-1)/p2),...a^((x-1)/pm)这m个数中,是否存在一个数mod x为1,若存在,a不是x的原根,不然就是x的原根。
原来的复杂度是O(P-1),如今变成O(m)*log(P-1)m为x-1质因子的个数。很明显质因子的个数远远小于x-1。
证实可用欧拉定理和裴蜀定理:
说明了对任何整数a、b和它们的最大公约数d,关于未知数x和y的线性丢番图方程(称为裴蜀等式):
ax + by = m
有解当且仅当m是d的倍数。裴蜀等式有解时必然有无穷多个整数解,每组解x、y都称为裴蜀数,可用展转相除法求得。
例如,12和42的最大公因子是6,则方程12x + 42y = 6有解。事实上有(-3)×12 + 1×42 = 6及4×12 + (-1)×42 = 6。
特别来讲,方程 ax + by = 1 有解当且仅当整数a和b互素。
裴蜀等式也能够用来给最大公约数定义:d其实就是最小的能够写成ax + by形式的正整数。这个定义的本质是整环中“理想”的概念。所以对于多项式整环也有相应的裴蜀定理。
那我来把下面的证实啰嗦地说一遍吧,防止有的同窗看不懂了。
1 假设x-1能够分解为p1~pm的幂次,Si=(x-1)/pi;
那么假设a的S1~Sm幂次存在一个等于1的数,那么显然这个不是咱们要的答案,由于他构成互不相同的元素集合
2 那么若是a的S1~Sm次方都没有等于1的,此时咱们用反证法来证实再没有因子能使得a的幂次等于1 3 假设存在一个t<phi(x)=x-1使得a^t = 1 (mod x) 4 5 由裴蜀定理,必定存在一组k,r使得kt=(x-1)r+gcd(t,x-1) 6 7 由欧拉定理有,a^(x-1) = 1 (mod x) 8 9 因而由上述三个等式 1 = a^(kt) = a^(xr-r+gcd(t,x-1)) = a^gcd(t,x-1) (mod x) 10 11 而t<x-1故gcd(t,x-1)<x-1 12 (而咱们知道一个数被分解质因数以后,他的因子必能写成他的质因子的乘积,故因子最小为p1~pm
因此比x-1小的尽可能包含尽量多因数的状况最多有多少种呢,显然让他减去最小的质因子的一个幂次就能够也就是,x-1/pi) 13 又gcd(t,x-1)|x-1 因而gcd(t,x-1)必整除(x-1)/p1,(x-1)/p2...(x-1)/pm其中至少一个,设其一为(x-1)/pi 14 15 那么a^((x-1)/pi) = (a^gcd(t,x-1))^s = 1^s = 1 (mod x) 16 17 那么这个假设与Si中没有能使a^Si=1的前提矛盾,故,在任意a^Si!=1时,再也没有比x-1小的数t能使a^t=1
这里的存在是说。。那m个数中是否有一个是mod =1
反证法很明白。。对于裴蜀定理。。这个是无条件成立的。。任意两个数都能找到,pa+qb=gcd(a,b)
而后咱们为何只枚举这m个数呢。。由于这是m个最大的约数的状况,这些状况包含了phi(x)的最小的因子的幂次的全部状况
若是枚举了phi(x)/pi那么就没有必要枚举phi(x)/pi^2,由于若是phi(x)/pi能检测出来mod以后等于1,那么phi(x)/pi^2就不用检测
若是不能检测的话,那么后面那个也是不能检测的。。