Pollard Rho算法

news2024/9/27 5:35:17

生日悖论

假设一年有 n n n天,房间中有 k k k人,每个人的生日在这 n n n天中,服从均匀分布,两个人的生日相互独立
问至少要有多少人,才能使其中两个人生日相同的概率达到 p p p

解:考虑 k ≤ n k\le n kn
k k k个人生日互不相同为事件 A A A,则
P ( A ) = n n n − 1 n ⋯ n − k + 1 n P\left(A\right)=\frac{n}{n}\frac{n-1}{n}\cdots\frac{n-k + 1}{n} P(A)=nnnn1nnk+1
由题意 P ( A ) ≤ 1 − p P\left(A\right) \le 1-p P(A)1p,由 1 + x ≤ e x 1+x \le e^{x} 1+xex
P ( A ) ≤ e − 1 n e − 2 n ⋯ e k − 1 n = e − k ( k − 1 ) 2 n ≤ 1 − p P\left(A\right) \le e^{-\frac{1}{n}} e^{-\frac{2}{n}}\cdots e^{\frac{k-1}{n}}=e^{-\frac{k\left(k-1\right)}{2n}} \le 1-p P(A)en1en2enk1=e2nk(k1)1p
解得
k ≥ 1 + 1 − 2 n ln ⁡ ( 1 − p ) 2 k \ge \frac{1 + \sqrt{1-2n\ln\left(1-p\right)}}{2} k21+12nln(1p)

n = 365 , p = 1 2 n=365,p=\frac{1}{2} n=365,p=21时, k = 23 k=23 k=23,也就是说一个房间中至少23人就能使其中两个人生日相同的概率达到 50 % 50\% 50%
由于这个事实十分反直觉,故称为一个悖论
在这里插入图片描述

Pollard-Rho算法

Pollard-Rho算法是一种用于快速分解非平凡因数的算法
通过 f ( x ) = ( x 2 + c ) m o d n f\left(x\right) = \left(x^2 + c\right) \mathop{mod} n f(x)=(x2+c)modn来生成一个随机数序列 { x i } \left\{x_i\right\} {xi},其中 c c c是一个随机数
随机取一个 x 1 x_1 x1,令 x 2 = f ( x 1 ) , ⋯   , x i = f ( x i − 1 ) x_2=f\left(x_1\right),\cdots,x_i=f\left(x_{i-1}\right) x2=f(x1),,xi=f(xi1),
这样产生的序列会形成一个 ρ \rho ρ,也就是说会产生一个环
在这里插入图片描述

∀ k ∈ N + , g c d ( k , n ) ∣ n \forall k \in \mathbb{N}_+, gcd\left(k,n\right)\mid n kN+,gcd(k,n)n,只要选取适当的 k k k使得 1 < g c d ( k , n ) < n 1< gcd\left(k,n\right)<n 1<gcd(k,n)<n,就能得到一个约数 g c d ( k , n ) gcd\left(k,n\right) gcd(k,n)
满足这样的条件的 k k k不少, k k k有若干质因子,每个质因子及其倍数都是可行的

由生日悖论,伪随机数序列中不同值的数量约为 O ( n ) O\left(\sqrt{n}\right) O(n )(怎么算出来的其实我也不知道 )
m m m n n n的最小非平凡因子,显然 m ≤ n m \le \sqrt{n} mn ,令 y i = x i m o d m y_i = x_i \mathop{mod} m yi=ximodm
1 ≤ c < n 1\le c < n 1c<n,则
y i + 1 = x i + 1 m o d m = ( ( x i 2 + c ) m o d n ) m o d m = ( x i 2 + c ) m o d m = ( ( x i m o d m ) 2 + c ) m o d m = ( y i 2 + c ) m o d m \begin{aligned} y_{i+1} & = x_{i+1} \mathop{mod} m\\ &=\left(\left(x_i^2 +c\right)\mathop{mod} n\right)\mathop{mod}m\\ &=\left(x_i^2 + c\right)\mathop{mod}m\\ &=\left(\left(x_i \mathop{mod} m\right)^2 + c\right)\mathop{mod} m\\ &=\left(y_i^2 + c\right)\mathop{mod} m \end{aligned} yi+1=xi+1modm=((xi2+c)modn)modm=(xi2+c)modm=((ximodm)2+c)modm=(yi2+c)modm
于是我们可以得到新的序列 { y i } \left\{y_i\right\} {yi}并且根据生日悖论可以得知序列中不同值的个数约为 O ( m ) ≤ O ( n 1 4 ) O\left(\sqrt{m}\right) \le O\left(n^{\frac{1}{4}}\right) O(m )O(n41)

假设存在两个位置 i , j i,j i,j,使得 x i ≠ x j x_i\neq x_j xi=xj y i = y j y_i =y_j yi=yj,则 n ∤ ∣ x i − x i ∣ n \nmid \left|x_i-x_i\right| nxixi m ∣ ∣ x i − x j ∣ m|\left|x_i-x_j\right| mxixj
进而 1 < g c d ( ∣ x i − x j ∣ , n ) < n 1<gcd\left(\left|x_i-x_j\right|, n\right)<n 1<gcd(xixj,n)<n
因此我们可以通过 g c d ( ∣ x i − x j ∣ , n ) gcd\left(\left|x_i-x_j\right|, n\right) gcd(xixj,n)获得 n n n的一个非平凡因子

floyd判环

a = f ( a ) a = f(a) a=f(a)
b = f ( f ( b ) b=f(f(b) b=f(f(b)
如果 a = b a=b a=b则有环,就直接返回,更换个 c c c再来一遍
如果 g c d ( ∣ a − b ∣ ) > 1 gcd\left(\left|a-b\right|\right)>1 gcd(ab)>1,则得到了一个因数

洛谷P4718
__int128 + 优化gcd + 7个数字判断质数 + O2才能过(不开O2会T第13个点)

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <ctime>
using namespace std;
typedef long long LL;
LL gcd(LL x, LL y){
    if (!x) return y;
    if (!y) return x;
    LL t = __builtin_ctzll(x | y);
    x >>= __builtin_ctzll(x);
    do
    {
        y >>= __builtin_ctzll(y);
        if (x > y) swap(x, y);
        y -= x;
    } while (y);
    return x << t;
}
LL quick_pow(LL a, LL b, LL p) {
    LL res = 1;
    while (b) {
        if (b & 1)res = (__int128)res * a % p;
        a = (__int128)a * a % p;
        b >>= 1;
    }
    return res;
}
const LL bases[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
bool Rabin_Miller(LL n) {
    if (n < 3 || (n & 1) == 0)return n == 2;

    LL u = n - 1, t = 0;
    // n - 1 = u * (2^t)
    while ((u & 1) == 0) {
        u >>= 1;
        ++t;
    }
    for (int i = 0; i < 7; ++i) {
        LL a = bases[i] % n;
        if (a == 0)continue;
        LL v = quick_pow(a, u, n);
        if (v == 1)continue;
        LL s;
        for (s = 0; s < t; ++s) {
            //a^{u * 2^s}= -1 (mod n)
            if (v == n - 1)break;
            v = (__int128)v * v % n;
        }
        if (s == t)return false;
    }
    return true;
}
LL max_factor;
LL f(LL x, LL c, LL p) {
    return ((__int128)x * x % p + c) % p;
}
LL getRandom(const LL& a, const LL& b) {
    return ((1LL * rand() << 32LL) + 1LL * rand()) % (b - a + 1LL) + a;
}
LL Pollard_Rho_floyd(LL x) {
    if (x == 4)return 2;
    LL c = getRandom(3, x - 1);//[3,x-1]
    LL s = getRandom(0, x - 1);//[0,x-1]
    s = f(s, c, x);
    LL t = f(s, c, x);
    while (s != t) {
        LL d = gcd(abs(t - s), x);
        if (d > 1)return d;
        s = f(s, c, x);
        t = f(f(t, c, x), c, x);
    }
    return x;
}
void fac(LL x) {
    if (x <= max_factor || x < 2)return;
    if (Rabin_Miller(x)) {// x是质数
        if (x > max_factor) {
            max_factor = x;
        }
        return;
    }
    LL p = x;
    while (p >= x)p = Pollard_Rho_floyd(x);//找一个因子p
    while (x % p == 0)x /= p;
    fac(x);
    fac(p);
}
int main() {
    srand((unsigned)time(NULL));
    int T;
    scanf("%d", &T);
    while (T--) {
        max_factor = 1;
        LL n;
        scanf("%lld", &n);
        fac(n);
        if (n == max_factor)printf("Prime\n");
        else printf("%lld\n", max_factor);
    }
    return 0;
}

倍增优化

由于频繁使用gcd会导致复杂度上去,
我们考虑累积几次再算gcd
下面是 m i n ( 2 k − 1 , 128 ) min\left(2^k -1, 128\right) min(2k1,128)次算一个gcd

洛谷P4718
__int128

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <ctime>
using namespace std;
typedef long long LL;
LL gcd(LL a, LL b){
    LL c;
    while (b){
        c = a % b;
        a = b;
        b =c;
    }
    return a;
}
LL quick_pow(LL a, LL b, LL p) {
    LL res = 1;
    while (b) {
        if (b & 1)res = (__int128)res * a % p;
        a = (__int128)a * a % p;
        b >>= 1;
    }
    return res;
}
const LL bases[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
bool Rabin_Miller(LL n) {
    if (n < 3 || (n & 1) == 0)return n == 2;

    LL u = n - 1, t = 0;
    // n - 1 = u * (2^t)
    while ((u & 1) == 0) {
        u >>= 1;
        ++t;
    }
    for (int i = 0; i < 7; ++i) {
        LL a = bases[i] % n;
        if (a == 0)continue;
        LL v = quick_pow(a, u, n);
        if (v == 1)continue;
        LL s;
        for (s = 0; s < t; ++s) {
            //a^{u * 2^s}= -1 (mod n)
            if (v == n - 1)break;
            v = (__int128)v * v % n;
        }
        if (s == t)return false;
    }
    return true;
}
LL max_factor;
LL f(LL x, LL c, LL p) {
    return ((__int128)x * x % p + c) % p;
}
LL getRandom(const LL& a, const LL& b) {
    return ((1LL * rand() << 32LL) + 1LL * rand()) % (b - a + 1LL) + a;
}
LL Pollard_Rho(LL x) {
    if (x == 4)return 2;
    LL c = getRandom(3, x - 1);//[3,x-1]
    LL s = getRandom(0, x - 1);//[0,x-1]
    s = f(s, c, x);
    LL t = f(s, c, x);
    for (int lim = 1; s != t; lim = std::min(128, lim << 1)) {
        LL val = 1;
        for (int i = 0; i < lim; ++i) {
            LL temp = (__int128)val * abs(s-t) % x;
            if (temp == 0)break;
            val = temp;
            s = f(s, c, x);
            t = f(f(t, c, x), c, x);
        }
        LL d = gcd(val, x);
        if (d > 1)return d;
    }
    return x;
}
void fac(LL x) {
    if (x <= max_factor || x < 2)return;
    if (Rabin_Miller(x)) {// x是质数
        if (x > max_factor) {
            max_factor = x;
        }
        return;
    }
    LL p = x;
    while (p >= x)p = Pollard_Rho(x);//找一个因子p
    while (x % p == 0)x /= p;
    fac(x);
    fac(p);
}
int main() {
    srand((unsigned)time(NULL));
    int T;
    scanf("%d", &T);
    while (T--) {
        max_factor = 1;
        LL n;
        scanf("%lld", &n);
        fac(n);
        if (n == max_factor)printf("Prime\n");
        else printf("%lld\n", max_factor);
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/170439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring框架介绍及使用

文章目录1.概述1.1 Spring是什么1.2 Spring 的优势1.3 spring 的体系结构2. IoC 的概念和作用2.1 什么是程序的耦合2.2 IoC容器3. AOP的概念和作用超链接&#xff1a; Spring重点内容学习资料1.概述 1.1 Spring是什么 Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源…

使用docker-compose搭建Prometheus+Grafana监控系统

一、角色分配 Prometheus 采集数据Grafana 用于图表展示redis_exporter 用于收集redis的metricsnode-exporter 用于收集操作系统和硬件信息的metricscadvisor 用于收集docker的相关metrics 二、安装Docker 可以参考&#xff1a;https://ximeneschen.blog.csdn.net/article/d…

JVM调优实战:to-space exhausted Evacuation Failure

一次线上dubbo问题的定位&#xff0c;进行JVM调优实战。问题线上dubbo接口provider抛出异常&#xff1a;org.apache.dubbo.rpc.RpcException: Failfast invoke providers ... RandomLoadBalance select from all providers ... use dubbo version 2.7.16, but no luck to perfo…

vulnhub DC系列 DC-8

总结&#xff1a;exim4提权 目录 下载地址 漏洞分析 信息收集 网站爆破 后台webshell 提权 下载地址 DC-8.zip (Size: 379 MB)Download: http://www.five86.com/downloads/DC-8.zipDownload (Mirror): https://download.vulnhub.com/dc/DC-8.zip使用方法:解压后&#xff…

Cosmos 基础(二)-- Ignite CLI

官网 DOC GitHub 你的项目值得拥有自己的区块链。 Ignite使开发、增长和启动区块链项目比以往任何时候都更快。 Ignite CLI是一个一体化平台&#xff0c;可以在主权和安全的区块链上构建、启动和维护任何加密应用程序 Install Ignite 一、安装 你可以在基于web的Gitpod…

23种设计模式(七)——桥接模式【单一职责】

文章目录 意图什么时候使用桥接真实世界类比桥接模式的实现桥接模式的优缺点亦称:Bridge 意图 桥接模式是将抽象部分与实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interfce)模式。 什么时候使用桥接 1、如果一个…

详解MySQL数据库索引实现机制 - B树和B+树

详解MySQL数据库索引实现机制 - B树和B树1.索引的出现2.hash算法的缺点3.二叉排序树BST4.平衡二叉树AVL5.红黑树6.B树诞生了7.B树1.索引的出现 索引是一种用于快速查询和检索数据的数据结构&#xff0c;其本质可以看成是一种排序好的数据结构。 索引的作用就相当于书的目录。…

(Netty)Handler Pipeline

Handler & Pipeline ChannelHandler 用来处理 Channel 上的各种事件&#xff0c;分为入站、出站两种。所有 ChannelHandler 被连成一串&#xff0c;就是 Pipeline 入站处理器通常是 ChannelInboundHandlerAdapter 的子类&#xff0c;主要用来读取客户端数据&#xff0c;写…

【嵌入式处理器】CPU、MPU、MCU、DSP、SoC、SiP的联系与区别

1、CPU(Central Processing Unit) CPU(Central Processing Unit)&#xff0c;是一台计算机的运算核心和控制核心。CPU由运算器、控制器和寄存器及实现它们之间联系的数据、控制及状态的总线构成。众所周知的三级流水线&#xff1a;取址、译码、执行的对象就是CPU&#xff0c;差…

重学Android之View——TabLayoutMediator解析

重学Android之View——TabLayoutMediator解析 1.前言 在使用TabLayoutViewPager2Fragment的时候&#xff0c;查询别人的使用例子&#xff0c;看到了 TabLayoutMediator这个类&#xff0c;撰写此文&#xff0c;仅当学习思考&#xff0c;本文是在引用material:1.7.0的版本基础…

记2022年秋招经历

自我介绍求职体验求职心得 一、自我介绍 学历普通本科&#xff0c;专业是网络工程&#xff0c;在校期间学习主要的是计算机体系方面的知识&#xff0c;根据课程&#xff0c;自学过前端、后端等内容。包括前端三板斧(htmlcssjs)、常用的前端框架(bootstarp/Vue等&#xff09;&am…

Android项目接入React Native方案

本篇文章主要介绍在现有的Android项目中接入React Native的接入过程&#xff0c;分析接入过程中的一些问题和解决方案&#xff0c;接入RN的平台为Android&#xff0c;开发环境为Mac&#xff0c;开发工具为Android Studio。 一、环境配置 1、Android配置 因为是现有的Android项…

Vue实现DOM元素拖放互换位置

一、拖放和释放HTML 拖放接口使得 web 应用能够在网页中拖放文件。这里将介绍了 web 应用如何接受从底层平台的文件管理器拖动DOM的操作。拖放的主要步骤是为 drop 事件定义一个释放区(释放文件的目标元素) 和为dragover事件定义一个事件处理程序。触发 drop 事件的目标元素需要…

day20IO流

1.字符流 1.1为什么会出现字符流【理解】 字符流的介绍 由于字节流操作中文不是特别的方便&#xff0c;所以Java就提供字符流 字符流 字节流 编码表 中文的字节存储方式 用字节流复制文本文件时&#xff0c;文本文件也会有中文&#xff0c;但是没有问题&#xff0c;原因是最…

数学建模-分类模型(SPSS)

目录 1.简介 2.样例-二元 1.对于预测结果不理想&#xff0c;在logistics模型里加入平方项交互项等。 2.如果自变量有分类变量&#xff08;如男女&#xff0c;行业有互联网行业、旅游行业……&#xff09; 3.分训练集、测试集 4.fisher线性判别分析 3.样例-多元 注意&…

【Nginx】使用Docker完成Nginx反向代理

本机是在CentOS7上面进行操作的 1.首先安装好Dokcer&#xff0c;这里不再赘述 2.Docker安装Nginx容器 2.1首先需要创建Nginx配置文件&#xff0c;之后完成挂载 启动前需要先创建Nginx外部挂载的配置文件&#xff08; /home/nginx/conf/nginx.conf&#xff09; 之所以要先创建…

Redis - Redis 6.0 新特性之客户端缓存

1. 为什么需要客户端缓存 antirez 写了一篇有关客户端缓存设计的想法&#xff1a;《Client side caching in Redis 6》。antirez 认为&#xff0c;Redis 接下来的一个重点是配合客户端&#xff0c;因为客户端缓存显而易见的可以减轻 Redis 的压力&#xff0c;速度也快很多。实…

Android从开机到APP启动流程——基于Android9.0

Android从开机到APP启动流程——基于Android9.0 一、 Zygote进程启动流程 二、 System Server启动流程 三、 ActivityManagerService启动流程 四、 Launcher App (Home Activity)启动流程 五、 Zygote fork()子进程&#xff0c;子进程入口为ActivityThread.main() 六、 Acti…

第02讲:使用kubeadm搭建k8s集群的准备工作

官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/ kubeadm 是官方社区推出的一个用于快速部署 kubernetes 集群的工具&#xff0c;这个工具能通过两条指令完成一个 kubernetes 集群的部署: 第1步、创建一个 Master 节点 kubeadm init第2步&#x…

记录一次mysql慢查询的优化过程

前言 业务上线后经常报查询超时&#xff0c;数据库使用的是阿里云的RDS&#xff0c;mysql版本是5.6.16-log&#xff0c;有几条统计数据的查询语句执行很慢&#xff0c;有的甚至执行一次需要10多秒&#xff0c;简直无法忍受。 查看了超时时间&#xff0c;默认为0 show variables…