Miller_Rabin算法

为了测试一个大整数是不是素数,我们不能够使用传统的测试是否有因子的方法,因为那样的时间复杂度至少也是O(n)O(n)O(n),空间复杂度是O(n)O(n)O(n)(使用线性筛数法),时间复杂度还好说,空间复杂度在n比较大的时候完全不可以接受,这就需要我们使用Miller_RabinMiller\_RabinMiller_Rabin算法进行解决。

算法的核心使用了费马小定理和二次探测定理

费马小定理:若ppp为质数,则ap−1≡1(modp)a^{p-1}\equiv 1\pmod pap11(modp)

这是一个质数的必要条件,但是有一类特殊的数也满足这个等式并且是合数(卡米歇尔数),为了剔除这些特殊的数,我们还需要二次探测定理帮助判断

二次探测定理:如果ppp为素数,x2≡1(modp)x^2\equiv 1 \pmod px21(modp),则x=1或x=p−1x=1 或 x=p-1x=1x=p1

因此对于满足费马小定理的数ppp,即ap−122≡1(modp){a^{\frac{p-1}{2}}}^2\equiv 1\pmod pa2p121(modp),我们判断ap−12a^{\frac{p-1}{2}}a2p1是否为1或者p−1p-1p1,如果不是说明ppp不是素数,如果是我们可以继续对ap−12a^{\frac{p-1}{2}}a2p1进行探测

每一次检测都无法100%确定这是一个素数,但是判断8次几乎不可能出错。

这里的mult函数是乘积函数,因为接近long long 的数字相乘会爆long long,这里按位相乘。

在研究的很多人的实现后我实现了以下,觉得我这个复杂度低一些(因为自己写的缘故看起来很亲切)。实际过题时间也比之前看到的快。

typedef long long ll;
ll mult(ll x,ll y,ll p)
{long double d=1; d=d*x/p*y;return ((x*y-((ll)d)*p)%p+p)%p;
}ll quick_pow(ll a,ll b,ll p)
{a%=p; ll ret=1;while(b){if(b&1) ret=mult(ret,a,p);a=mult(a,a,p); b>>=1;}return ret;
}bool Miller_Rabin(ll n)
{if(n<2) return false;const int times=8;const ll prime[times]={2,3,5,7,11,13,17,61};for(int i=0;i<times;i++)if(n==prime[i]) return true;else if(n%prime[i]==0) return false;ll x=n-1; while(~x&1) x>>=1;for(int i=0;i<times;i++){ll a=prime[i]; ll now=quick_pow(a,x,n); ll last;if(x==n-1){if(now!=1) return false;}else{while(x!=n-1){x<<=1; last=now; now=mult(now,now,n);if(now==1){if(last!=1 && last!=n-1) return false;break;}}}}return true;
}

之前看到的别人的板子

ll mult(ll a, ll b, ll p) {a %= p;b %= p;ll res = 0, tmp = a;while(b) {if (b & 1) {res += tmp;if (res > p) res -= p;}tmp <<= 1;if (tmp > p) tmp -= p;b >>= 1;}return res;
}ll quick_pow(ll a, ll b, ll p) {ll res = 1;ll tmp = a % p;while(b) {if (b & 1) res = mult(res, tmp, p);tmp = mult(tmp, tmp, p);b >>= 1;}return res;
}bool check(ll a, ll n, ll x, ll t) {ll res = quick_pow(a, x, n);ll last = res;for (ll i = 1; i <= t; i++) {res = mult(res, res, n);if (res == 1 && last != 1 && last != n-1) return true;last = res;}return res != 1;
}bool Miller_Rabin(ll n) {if (n < 2) return false;if (n == 2) return true;if ((n & 1) == 0) return false;ll x = n-1;ll t = 0;while ((x & 1) == 0) {x >>= 1;t++;}srand(time(NULL));const ll tims = 8;for (ll i = 0; i < tims; i++) {ll a = rand() % (n-1) + 1;if (check(a, n, x, t)) return false;}return true;
}

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

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

相关文章

bob-tong 字符串函数之Strtok()函数

https://www.cnblogs.com/Bob-tong/p/6610806.html Strtok()函数详解&#xff1a; 该函数包含在"string.h"头文件中 函数原型&#xff1a; char* strtok (char* str,constchar* delimiters ); 函数功能&#xff1a;   切割字符串&#xff0c;将str切分成一个个子…

数据链路层:SLIP(串型线路IP) PPP(点对点协议)

SLIP 没有差错控制, 传输时必须知道对方IP, 传输使用于低速业务 19.2k.应用非常受限 PPP协议 1. PPP协议功能 处理错误检测 支持多协议(IP, IPX, DECnet 等) 连接时允许协商 IP 地址 允许身份验证 2. PPP 的组成 串型链路上封装数据报, 即支持异步链路也支持面向 比特…

Honeycomb——BFS

【题目描述】 传送门 【题目分析】 看起来很复杂好像还要建图什么的&#xff0c;其实直接在原图上BFS就可以了&#xff0c;设置一下方向数组&#xff0c;然后直接跑就可以了。 【AC代码】 #include<cstdio> #include<cstring> #include<algorithm> #inc…

C语言中strspn()函数和strcspn()函数的对比使用

C语言strspn()函数&#xff1a;计算字符串str中连续有几个字符都属于字符串accept 头文件&#xff1a;#include <string.h> strspn() 函数用来计算字符串 str 中连续有几个字符都属于字符串 accept&#xff0c;其原型为&#xff1a; size_t strspn(const char *str, con…

Codeforces Round #587 (Div. 3)

A 只要每两个都不一样就可以&#xff0c;一旦出现两个一样的就改一个。 #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #include<cctype> #include<queue> #include<set>using namespace std;typede…

信道分配 以太网

1.频分复用 将信道分为多个频带, 用户得到某个频带后,在通信的过程中, 自始至终都都占用这个信道.即频分复用中, 所有用户同时占用不同频带的信道 2. 时分信道 将时间划分为一段一段的等长时分复用帧, 每个用户在不同时间占用相同的数据帧 3. CSMA/CD 载波监听多点接入/碰撞…

strpbrk函数

http://blog.csdn.net/tommy_wxie/article/details/7554332 函数原型&#xff1a;extern char *strpbrk(char *str1, char *str2) 参数说明&#xff1a;str1待比较的字符串&#xff0c;str2为指定被搜索的字符串。 所在库名&#xff1a;#include <string.h> …

网络层网络层服务及其 IP 地址

ARP 协议功能 将 IP 地址通过广播(一个网段, 不能跨路由器), 目标 MAC 地址是FFFFFFFF 解析目标IP地址的 MAC 地址. IP 协议 网络层的一个协议, 是一个协议的统称, 包括 ARP(地址解析协议) 协议, ICMP(网络控制报文协议) 协议, IGMP(网际组管理协议) 协议. 其中 ICMP 和 IG…

随机生成1024个数,存入一段内存,用指针实现获取1024个数的最大数地址,最小数地址

http://blog.csdn.net/itcastcpp//details/39277193 题目&#xff1a;随机生成1024个数&#xff0c;存入一段内存&#xff0c;用指针实现获取1024个数的最大数地址&#xff0c;最小数地址&#xff0c;具体实现如下&#xff1a; [cpp] view plaincopy #include<stdlib.h> …

UVa11134

【题目分析】 觉得是一道挺考验贪心掌握程度的题目&#xff0c;我就算知道是要用贪心而且肯定和区间有关&#xff0c;肯定要进行一下排序什么的我还是没有找到合适的贪心策略。 经过大佬的博客后我才明白如何进行贪心。 如果没有任何提示看这道题&#xff0c;首先&#xff0…

传输层:IP 地址解析 路由转发

IP 地址与硬件地址 1. 地址解析 通过IP地址将其如何转换为 MAC 地址.解决同一个局域网上的主机或路由的 IP 地址和硬件地址的映射问题. 即以太网上除了主机还有路由. 即如果发出的请求所有的主机都没有做出相应, 那么该以太网上的路由会对其做出响应. (1) 以太网内部主机与…

UVa11582

一个数学问题,一旦出现循环确定循环节以后就能解决问题啦. 加上一个快速幂取模.需要注意的是数据范围是264,所以必须用unsigned long long才能解决问题. 觉得板子还是要会自己写,否则不同的题目具体有一些小的改变就会束手无策. 还有就是发现如果每次初始化数组的话就会超时,所…

输入一个单向链表,输出该链表中倒数第K个结点

http://blog.csdn.net/itcastcpp/article/details/39274891//尹成 单链表操作 #include <iostream> using namespace std; class LinkList;struct LinkNode { public:LinkNode(int value 0):m_value(value),pNext(NULL){}~LinkNode(){pNext NULL;}friend class LinkList…

网络层:构成超网(CIDR)

CIDR构成超网 CIDR消除了原来的传统的 A,B, C, D类地址, 使用了各种网络前缀来代替原来分类地址中的网络号和子网号, IP 地址由原来的三级分类又变成了两级分类. 其中网络号和子网号是一个随机的长度. 其中 CIDR 也可以使用 / 的形式来表示, 其中在 / 前面写上网络前缀的位数.…

UVa12169

我们可以暴力枚举a,然后通过x1和x3确定b的值&#xff0c;然后确定其他的数字&#xff0c;一旦出现错误就放弃这组解。 关键问题就在于如何通过a,x1,x3确定b的值 x2 ( x1 * a b) % M x3 ( x2 * a b ) % M ( ( x1 * a b ) % M * a b ) % M x3 - k * M x1 * a % M * a %…

尹成 双循环链表

今天&#xff0c;我们一起用C写一个双链表&#xff0c;具体代码如下&#xff1a; DoubleList.h具体内容如下&#xff1a; [cpp] view plaincopy #include "NodeList.h" template<typename Type> class DoublyList{ public: DoublyList() :head(ne…

堆的基本操作

堆的数据结构 对于堆, 有最大堆和最小堆, 在定义一个堆的时候用一个数组表示堆, 同时为了方便定义堆的大小, 用一个 size 表示堆的有效元素, 同时为了区别最大堆和最小堆, 我们用一个函数指针表示这个堆是最大堆还是最小堆. typedef int (*Compare)(HeapType parent, HeapTyp…

UVa1605

完完全全的构造题 一种比较好想到&#xff08;虽然我没有想到。。&#xff09;的方法是做成一个两层的表格&#xff0c;第一层每一行相同&#xff0c;第二层每一列相同&#xff0c;这样每个都能和其他的相邻了。 输出格式稍微注意一下 #include<cstdio> #include<c…

Linux下的TCP/IP编程----IO复用及IO复用服务端

http://blog.csdn.net/wqc_csdn/article/details/51583901 在之前我们实现的并发服务端时通过床将多个进程来实现的&#xff0c;这种并实现并发的方式简单方便&#xff0c;但是进程的创建和销毁是很消耗系统资源的&#xff0c;在访问量大时服务器很容易出现资源不够用的情况。除…

UVa120

相当于是一个模拟&#xff0c;为了得到合适的顺序&#xff0c;我们的策略是每次找到当前没有被翻的里面最大的&#xff0c;然后把他翻到最前面&#xff0c;然后再翻到合适的位置。 需要判断一下当前是否已经有序&#xff0c;有序就不用翻了。 如果在最开头找到了合适的当前应…