目录
例题完成进度
问题的提出
如何快速地找到一个自然数N的两个因数(除自己和1以外)?
首先想到的肯定是传统的试除法
int main(){ int N; cin>>N; if(N%2==0){ cout<<2<<" "<<N/2<<endl; return 0; } for(int i=3;i<=sqrt(N);i+=2){ //这里是一个优化了的试除法,可以直接排除偶数 if(N%i==0){ cout<<i<<" "<<N/i<<endl; return 0; } } cout<<"No!"<<endl; return 0; }
这里还有一个比较不走心的算法叫I am feeling lucky algorithm
这种算法的思想就是随机生成一个[2,N]的数,若恰好生成了N的因数,那么就输出,否则就停止.
那么这种算法成功(也就是恰好生成N的因数)的概率是多少呢?
我们来试想一下最坏的情况,就是在[2,N-1]的范围内,N恰好只有两个因数。
那么我们正好找到这两个因数其中之一的概率就是$\frac{2}{N-1}$。
如果N比较大,约为1010时,成功的概率约为$\frac{1}{5000000000}$,这比彩票中奖的概率还要小QAQ
这样当然是不行的,如果要确保找到一个因数,那么我们需要用不同的随机数判断将近N次,这样会比试除法还要暴力。
不过,虽然这个算法显然是不行的,但是它给我们提供了一个思路——随机。
生日悖论
如果你要从[1,1000]中随机取一个数,那么显然取得一个指定的数(假设为51)的概率为$\frac{1}{1000}$
把这个问题修改一下,如果我要从这1000个数中任意取两个数,使得这两个数的差的绝对值为51的概率又是多少呢?
因为会取绝对值,所以我们可以完全随机选择第一个数,也就是说,选择第一个数符合条件的概率是100%
又根据对称性可知,选中第二个数符合条件的情况有两种,概率为$\frac{2}{999}$
于是最后的总概率就约为$\frac{1}{500}$
如果我们再修改一下这个问题,从1000个数中任选出k=3,4,5……个数,那么可以发现,成功的概率是单调递增的
我们再来看看到底什么是生日悖论
就是随机选取一名学生,他的生日恰好为6月1日的概率为$\frac{1}{365}$
那么这相当于我们在[1,365]中选取任意一个数为指定的
利用生日悖论来因数分解
Pollard-rho算法
例题