【日常训练】Pollard's rho学习

开坑时间:2019.10.18周五

学习原因及其他

没什么原因,就是想学。有可能是因为今天在机房,csl到处问Pollard’s rho怎么写,我随即发现自己不会,决定去学习。

2019-10-18

入门

入门,初步学习:xyx的博客
初步了解Pollard’s rho的过程。认识到它的本质以及大致过程。

  • 要分解 N N N* 伪随机生成数列 A = { a 1 , a 2 , a 3 , . . . } A=\{a_1,a_2,a_3,...\} A={a1,a2,a3,...},每一项由前一项用固定方式推得。常用方式为 a i = f ( a i − 1 ) = ( a i − 1 2 + C ) m o d   N a_i=f(a_{i-1})=(a_{i-1}^2+C)mod\,N ai=f(ai1)=(ai12+C)modN其中 C C C为一不变常数。
  • 每次查看 g c d ( a 2 i − a i , N ) gcd(a_{2i}-a_i,N) gcd(a2iai,N),若不为1,说明此时找到了一个约数 g c d ( a 2 i − a i , N ) gcd(a_{2i}-a_i,N) gcd(a2iai,N)。若此时 g c d ≠ N gcd\neq N gcd=N,说明我们确实找到了一个非平凡约数。但如果 g c d = N gcd=N gcd=N,就没有找下去的必要了。
  • 这实际上是找到了循环节。即,如果最终我们有一个因数 P P P,那么 a i   m o d   P a_i\,mod\,P aimodP实际是有循环节的。当 g c d ≠ 1 gcd\neq 1 gcd=1是,我们发现 a 2 i a_{2i} a2i a i a_i ai实际上就到了循环节上一个相同的位置。
  • 如果此时 g c d = N gcd=N gcd=N,就说明 a 2 i a_{2i} a2i a i a_i ai也到了 m o d   N mod\,N modN循环节上的同一位置。这就说明不行了,我们要换一个 C C C
  • 我们假设要经过 Q Q Q步进入循环节,循环节长 R R R步,那么 a 2 i a_{2i} a2i a i a_{i} ai要对应上循环节同一点,所需时间是 O ( Q + R ) O(Q+R) O(Q+R)的。* 所以这个算法的关键就是期望多少次, a i   m o d   P a_i\,mod\,P aimodP会冲突。生日悖论告诉我们是 O ( P ) O(\sqrt{P}) O(P ) O ( N 1 4 ) O(N^{\frac{1}{4}}) O(N41)

生日悖论

进一步学习:关于生日悖论发现一篇文章:一篇文章这篇文章关于生日悖论讲了一些。可以帮助理解为什么会在很快的时间内成功,但是没有证明期望。

关于名字

发现了为什么要叫Pollard’s rho:因为循环节这东西长得很像 ρ \rho ρ

关于 a 2 i − a i a_{2i}-a_i a2iai

这东西实际上就是Floyd的找环算法。

2019-10-21

代码1

LL PR_zuo(LL cn,LL a)
{
	LL lin1 = 2, lin2 = get_ne(lin1,a,cn), lin3;
	while(1)
	{
		lin3 = gcd((lin2-lin1+cn)%cn, cn);
		if(lin3 != 1) return lin3 == cn ? 0 : lin3;
		lin1 = get_ne(lin1,a,cn); lin2 = get_ne(get_ne(lin2,a,cn),a,cn);
	}
}
LL Pollard_rho(LL cn)
{
	if(cn == 1) return 1;
	if(!(cn&1)) return 2;
	if(Miller_Rabin(cn)) return cn;
	LL a = 4, lin;
	while(1) {if(lin = PR_zuo(cn,a)) return lin; a += 3; }
}

这份代码时间复杂度 O ( N 1 4 α ( N ) ) O(N^{\frac{1}{4}}\alpha(N)) O(N41α(N)) ,其中 α ( N ) \alpha(N) α(N)表示求 O ( N ) O(N) O(N)大小的两个数的gcd的时间复杂度。

代码2

LL PR_zuo(LL cn,LL a)
{
	LL lin1 = 2, lin2 = get_ne(lin1,a,cn), lin3;
	int B = 100;
	while(1)
	{
		LL lin = 1, lin4 = lin1, lin5 = lin2;
		for(int i = 1;i<=B;i++) 
		{
			lin = ksc(lin,(lin5-lin4+cn)%cn,cn);
			lin4 = get_ne(lin4,a,cn); lin5 = get_ne(get_ne(lin5,a,cn),a,cn);
		}
		lin3 = gcd(lin,cn);
		if(lin3 != 1) {if(lin3 != cn) return lin3; break; }
		lin1 = lin4; lin2 = lin5;
	}
	while(1)
	{
		lin3 = gcd((lin2-lin1+cn)%cn, cn);
		if(lin3 != 1) return lin3 == cn ? 0 : lin3;
		lin1 = get_ne(lin1,a,cn); lin2 = get_ne(get_ne(lin2,a,cn),a,cn);
	}
}
LL Pollard_rho(LL cn)
{
	if(cn == 1) return 1;
	if(!(cn&1)) return 2;
	if(Miller_Rabin(cn)) return cn;
	LL a = 4, lin;
	while(1) {if(lin = PR_zuo(cn,a)) return lin; a += 3; }
}

这份代码是 O ( N 1 4 + N 1 4 B α ( N ) + B α ( N ) ) O(N^{\frac{1}{4}}+\frac{N^{\frac{1}{4}}}{B}\alpha(N)+B\alpha(N)) O(N41+BN41α(N)+Bα(N)) B B B是一个选定的常数。

但是我这一份慢得很,不知道为什么。正在努力卡常。

2019-10-27

一个最新进展:我发现 a a a初值选得好,会让程序效率有一定的提升(大概20%)

13是一个不错的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值