Loading docs/math/pollar-rho.md +118 −139 Original line number Diff line number Diff line Loading @@ -20,8 +20,7 @@ $$ P(A)=\frac{n}{n} \times \frac{n-1}{n} \times \dots \times \frac{n-k+1}{n} $$ 至少有两个人生日相同的概率为$P(\overline A)=1-P(A)$。根据题意可知$P(\overline A)\ge\frac{1}{2}$ ,那么就有$1 \times \frac{n-1}{n} \times \dots \times \frac{n-k+1}{n} \le \frac{1}{2}$ 至少有两个人生日相同的概率为 $P(\overline A)=1-P(A)$ 。根据题意可知 $P(\overline A)\ge\frac{1}{2}$ , 那么就有 $1 \times \frac{n-1}{n} \times \dots \times \frac{n-k+1}{n} \le \frac{1}{2}$ 由不等式 $1+x\le e^x$ 可得 Loading @@ -34,7 +33,7 @@ $$ 然而我们可以得到一个不等式方程, $e^{-\frac{k(k-1)}{2n}}\le 1-p$ ,其中 $p$ 是一个概率。那么当 $k=57$ , $n=365$ 时,可以求得 $p\approx 0.99$ 。 考虑一个问题,设置一个数据$n$,在$[1,1000]$里随机选取$i$个数($i=1$时就是它自己),使它们之间有两个数的差值为$k$。当$i=1$时成功的概率是$\frac{1}{1000}$,当$i=2$时成功的概率是$\frac{1}{500}$(考虑绝对值,$k_2$可以取$k_1-k$或$k_1+k$),随着$i$的增大,这个概率也会增大最后趋向于1。 考虑一个问题,设置一个数据 $n$ ,在 $[1,1000]$ 里随机选取 $i$ 个数( $i=1$ 时就是它自己),使它们之间有两个数的差值为 $k$ 。当 $i=1$ 时成功的概率是 $\frac{1}{1000}$ ,当 $i=2$ 时成功的概率是 $\frac{1}{500}$ (考虑绝对值, $k_2$ 可以取 $k_1-k$ 或 $k_1+k$ ),随着 $i$ 的增大,这个概率也会增大最后趋向于 1。 ## 优化随机算法 Loading Loading @@ -66,13 +65,11 @@ $$ ??? note "基于Floyd判环的Pollar-Rho算法" ```c++ ll PR(ll N) { ll PR(ll N) { ll c = rand() % (N - 1) + 1; ll t = f(0, c, N); ll r = f(f(0, c, N), c, N); while(t != r) { while (t != r) { ll d = gcd(abs(t - r), N); if (d > 1) return d; t = f(t, c, N); Loading @@ -90,20 +87,16 @@ $$ ??? note "参考实现" ```c++ ll PR(ll x) { ll PR(ll x) { ll s = 0, t = 0; ll c = rand() % (x - 1) + 1; int step = 0, goal = 1; ll val = 1; for( goal=1; ;goal <<= 1, s = t, val = 1) { for(step = 1; step <= goal; ++step) { for (goal = 1;; goal <<= 1, s = t, val = 1) { for (step = 1; step <= goal; ++step) { t = f(t, c, x); val = val * abs(t - s) % x; if( (step % 127) == 0 ) { if ((step % 127) == 0) { ll d = gcd(val, x); if (d > 1) return d; } Loading @@ -114,8 +107,7 @@ $$ } ``` 例题:[P4718 【模板】Pollard-Rho算法](https://www.luogu.com.cn/problem/P4718) 例题: [P4718【模板】Pollard-Rho 算法](https://www.luogu.com.cn/problem/P4718) 对于一个数 n,用 [Miller Rabin 算法](/prime/#_4) 判断是否为素数,如果是就可以直接返回了,否则用 Pollard-Rho 算法找一个因子 p,将 n 除去因子 p。再递归分解 n 和 p,用 Miller Rabin 判断是否出现质因子,并用 max_factor 更新就可以求出最大质因子了。由于这个题目的数据过于庞大,用 Floyd 判环的方法是不够的,这里采用倍增优化的方法。 Loading @@ -131,19 +123,15 @@ $$ int t; ll max_factor, n; inline ll gcd(ll a,ll b) { inline ll gcd(ll a, ll b) { if (b == 0) return a; return gcd(b, a % b); } inline ll qp(ll x,ll p,ll mod) { inline ll qp(ll x, ll p, ll mod) { ll ans = 1; while(p) { if(p & 1) ans = (lll)ans * x % mod; while (p) { if (p & 1) ans = (lll)ans * x % mod; x = (lll)x * x % mod; p >>= 1; } Loading @@ -169,25 +157,18 @@ $$ return 1; } inline ll f(ll x,ll c,ll n) { return ((lll)x * x + c) % n; } inline ll f(ll x, ll c, ll n) { return ((lll)x * x + c) % n; } inline ll PR(ll x) { inline ll PR(ll x) { ll s = 0, t = 0; ll c = (ll)rand() % (x - 1) + 1; int step = 0, goal = 1; ll val = 1; for( goal=1; ;goal <<= 1, s = t, val = 1) { for(step = 1; step <= goal; ++step) { for (goal = 1;; goal <<= 1, s = t, val = 1) { for (step = 1; step <= goal; ++step) { t = f(t, c, x); val = (lll)val * abs(t - s) % x; if( (step % 127) == 0 ) { if ((step % 127) == 0) { ll d = gcd(val, x); if (d > 1) return d; } Loading @@ -197,11 +178,9 @@ $$ } } inline void fac(ll x) { inline void fac(ll x) { if (x <= max_factor || x < 2) return; if(Miller_rabin(x)) { if (Miller_rabin(x)) { max_factor = max(max_factor, x); return; } Loading @@ -211,17 +190,17 @@ $$ fac(x), fac(p); } int main() { int main() { scanf("%d", &t); while(t --) { while (t--) { srand((unsigned)time(NULL)); max_factor = 0; scanf("%lld", &n); fac(n); if(max_factor == n) printf("Prime\n"); else printf("%lld\n",max_factor); if (max_factor == n) printf("Prime\n"); else printf("%lld\n", max_factor); } return 0; } Loading Loading
docs/math/pollar-rho.md +118 −139 Original line number Diff line number Diff line Loading @@ -20,8 +20,7 @@ $$ P(A)=\frac{n}{n} \times \frac{n-1}{n} \times \dots \times \frac{n-k+1}{n} $$ 至少有两个人生日相同的概率为$P(\overline A)=1-P(A)$。根据题意可知$P(\overline A)\ge\frac{1}{2}$ ,那么就有$1 \times \frac{n-1}{n} \times \dots \times \frac{n-k+1}{n} \le \frac{1}{2}$ 至少有两个人生日相同的概率为 $P(\overline A)=1-P(A)$ 。根据题意可知 $P(\overline A)\ge\frac{1}{2}$ , 那么就有 $1 \times \frac{n-1}{n} \times \dots \times \frac{n-k+1}{n} \le \frac{1}{2}$ 由不等式 $1+x\le e^x$ 可得 Loading @@ -34,7 +33,7 @@ $$ 然而我们可以得到一个不等式方程, $e^{-\frac{k(k-1)}{2n}}\le 1-p$ ,其中 $p$ 是一个概率。那么当 $k=57$ , $n=365$ 时,可以求得 $p\approx 0.99$ 。 考虑一个问题,设置一个数据$n$,在$[1,1000]$里随机选取$i$个数($i=1$时就是它自己),使它们之间有两个数的差值为$k$。当$i=1$时成功的概率是$\frac{1}{1000}$,当$i=2$时成功的概率是$\frac{1}{500}$(考虑绝对值,$k_2$可以取$k_1-k$或$k_1+k$),随着$i$的增大,这个概率也会增大最后趋向于1。 考虑一个问题,设置一个数据 $n$ ,在 $[1,1000]$ 里随机选取 $i$ 个数( $i=1$ 时就是它自己),使它们之间有两个数的差值为 $k$ 。当 $i=1$ 时成功的概率是 $\frac{1}{1000}$ ,当 $i=2$ 时成功的概率是 $\frac{1}{500}$ (考虑绝对值, $k_2$ 可以取 $k_1-k$ 或 $k_1+k$ ),随着 $i$ 的增大,这个概率也会增大最后趋向于 1。 ## 优化随机算法 Loading Loading @@ -66,13 +65,11 @@ $$ ??? note "基于Floyd判环的Pollar-Rho算法" ```c++ ll PR(ll N) { ll PR(ll N) { ll c = rand() % (N - 1) + 1; ll t = f(0, c, N); ll r = f(f(0, c, N), c, N); while(t != r) { while (t != r) { ll d = gcd(abs(t - r), N); if (d > 1) return d; t = f(t, c, N); Loading @@ -90,20 +87,16 @@ $$ ??? note "参考实现" ```c++ ll PR(ll x) { ll PR(ll x) { ll s = 0, t = 0; ll c = rand() % (x - 1) + 1; int step = 0, goal = 1; ll val = 1; for( goal=1; ;goal <<= 1, s = t, val = 1) { for(step = 1; step <= goal; ++step) { for (goal = 1;; goal <<= 1, s = t, val = 1) { for (step = 1; step <= goal; ++step) { t = f(t, c, x); val = val * abs(t - s) % x; if( (step % 127) == 0 ) { if ((step % 127) == 0) { ll d = gcd(val, x); if (d > 1) return d; } Loading @@ -114,8 +107,7 @@ $$ } ``` 例题:[P4718 【模板】Pollard-Rho算法](https://www.luogu.com.cn/problem/P4718) 例题: [P4718【模板】Pollard-Rho 算法](https://www.luogu.com.cn/problem/P4718) 对于一个数 n,用 [Miller Rabin 算法](/prime/#_4) 判断是否为素数,如果是就可以直接返回了,否则用 Pollard-Rho 算法找一个因子 p,将 n 除去因子 p。再递归分解 n 和 p,用 Miller Rabin 判断是否出现质因子,并用 max_factor 更新就可以求出最大质因子了。由于这个题目的数据过于庞大,用 Floyd 判环的方法是不够的,这里采用倍增优化的方法。 Loading @@ -131,19 +123,15 @@ $$ int t; ll max_factor, n; inline ll gcd(ll a,ll b) { inline ll gcd(ll a, ll b) { if (b == 0) return a; return gcd(b, a % b); } inline ll qp(ll x,ll p,ll mod) { inline ll qp(ll x, ll p, ll mod) { ll ans = 1; while(p) { if(p & 1) ans = (lll)ans * x % mod; while (p) { if (p & 1) ans = (lll)ans * x % mod; x = (lll)x * x % mod; p >>= 1; } Loading @@ -169,25 +157,18 @@ $$ return 1; } inline ll f(ll x,ll c,ll n) { return ((lll)x * x + c) % n; } inline ll f(ll x, ll c, ll n) { return ((lll)x * x + c) % n; } inline ll PR(ll x) { inline ll PR(ll x) { ll s = 0, t = 0; ll c = (ll)rand() % (x - 1) + 1; int step = 0, goal = 1; ll val = 1; for( goal=1; ;goal <<= 1, s = t, val = 1) { for(step = 1; step <= goal; ++step) { for (goal = 1;; goal <<= 1, s = t, val = 1) { for (step = 1; step <= goal; ++step) { t = f(t, c, x); val = (lll)val * abs(t - s) % x; if( (step % 127) == 0 ) { if ((step % 127) == 0) { ll d = gcd(val, x); if (d > 1) return d; } Loading @@ -197,11 +178,9 @@ $$ } } inline void fac(ll x) { inline void fac(ll x) { if (x <= max_factor || x < 2) return; if(Miller_rabin(x)) { if (Miller_rabin(x)) { max_factor = max(max_factor, x); return; } Loading @@ -211,17 +190,17 @@ $$ fac(x), fac(p); } int main() { int main() { scanf("%d", &t); while(t --) { while (t--) { srand((unsigned)time(NULL)); max_factor = 0; scanf("%lld", &n); fac(n); if(max_factor == n) printf("Prime\n"); else printf("%lld\n",max_factor); if (max_factor == n) printf("Prime\n"); else printf("%lld\n", max_factor); } return 0; } Loading