博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj3667: Rabin-Miller算法
阅读量:4597 次
发布时间:2019-06-09

本文共 2308 字,大约阅读时间需要 7 分钟。

传送门:

思路:首先我们说说Miller_Rabin算法

我们发现了费马小定理

那它倒过来对不对呢

如果a^(p-1)=1(mod p),那么p一定是素数吗?

很不幸,是错的

虽然出错概率很低,但是可以被卡

于是我们就给它打补丁

我们又找到了一个二次探测的方法

如果p是质数,那么x^2=1(mod p)只有两个解1,p-1 (-1)

那么它倒过来对不对呢

很不幸,又是错的

但是两个错误算法加到一起,出错概率就很低了

那么我们先随机出一些数a[i]

每次拿出一个数a

先用费马小定理去测试

那么我们就要算a^(n-1)%n

把n-1拆成2^s*d的形式

这样我们就可以顺便进行二次探测了

先算出a^d次方

然后平方s次不就是a^(n-1)吗

平方的时候顺便检查一下

最后再用费马小定理检测即可

可以证明一次检测出错的概率是1/4

那么很多次后就几乎不出错了

然后就是pollard_rho了

设要分解的数是n

如果我们有两个随机数x,y

如果gcd(x-y,n)!=1&&gcd(x-y,n)!=n

那么p=gcd(x-y,n)是n的一个约数

随机根号n次(1,n)的数,就有很大概率有同样的数

那么随机根号p次,就很有可能有两个数的差是p的倍数了

这样我们就会走到一个环上,最后就相遇了、

实现时设计一个随机函数f(x)

设定k为此次暴力跳的路径长

每次倍长

x暴力迭代

每次做差求gcd

达到k次后把y赋为x

形象一点就是两个指针在rho型的东西上走

走到环上相同的点,就可以得到一个p的倍数,p是n的一个因子

然后把这个数和n求gcd,就有可能得到一个约数

先特判n是否为质数

然后因为有可能直接走到n的环,所以如果分解不出n之外的因子那就说明这个随机函数会使你直接走到n的环上,所以再换一个重试即可

拆出一个因数d后递归处理d和n/d即可

还有一点就是快速乘法,这题的模数是longlong的,但是又不想写高精度

一种处理是把乘法看做多次加法,类似快速幂去做

高端的O(1)做法是:

然后就可以解决这道模板题了

#include
#include
#include
#include
#include
#define abs(a) (a>0?a:-(a)) typedef long long ll; const ll a[]={2,3,5,7,11,13,17,19,23,29}; using namespace std; int cas;ll maxs; void read(ll &x){ char ch; for (ch=getchar();!isdigit(ch);ch=getchar()); for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; } ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);} ll mul(ll a,ll b,ll p){ ll d=((long double)a/p*b+1e-8); ll res=a*b-d*p; res=res<0?res+p:res; return res; } ll qpow(ll a,ll b,ll c){ ll res=1; for (;b;b>>=1,a=mul(a,a,c)) if (b&1) res=mul(res,a,c); return res; } bool check(ll a,ll n,ll r,ll s){ ll x=qpow(a,r,n),pre=x; for (int i=1;i<=s;i++){ x=mul(x,x,n); if (x==1&&pre!=1&&pre!=n-1) return 0; pre=x; } if (x!=1) return 0; return 1; } bool MR(ll n){ if (n<=1) return 0; ll r=n-1,s=0; while (!(r&1)) r>>=1,s++; for (int i=0;i<9;i++){ if (a[i]==n) return 1; if (!check(a[i],n,r,s)) return 0; } return 1; } ll pol_rho(ll n,ll c){ //printf("%lld %lld\n",n,c); ll k=2,x=rand()%n,y=x,p=1; for (ll i=1;p==1;i++){ x=(mul(x,x,n)+c)%n; p=y>x?y-x:x-y; p=gcd(n,p); if (i==k) y=x,k+=k; //cout<<" "<
<<' '<
<

转载于:https://www.cnblogs.com/thythy/p/5493624.html

你可能感兴趣的文章
查看oracle/mysql数据库版本号
查看>>
memset函数
查看>>
使用postman+newman+python做接口自动化测试
查看>>
实体框架继承关系。很好
查看>>
201671010110 2016 2017 2《java程序设计》
查看>>
flask的基础认识
查看>>
静态blog的免费托管部署、加域名与搜索优化(SEO)
查看>>
oracle trunc(d1[,c1])
查看>>
linux 内核定时器的实现
查看>>
Android和IOS等效MD5加密
查看>>
小房间灯.20190512
查看>>
绘图-路径
查看>>
恢复sudo的权限的命令
查看>>
使用appledoc
查看>>
转:Loadrunner添加服务器监控
查看>>
remove debug symbols to a seperate file
查看>>
ArcGIS ArcMap “ Add Data” 打开后,一直卡死,无内容
查看>>
在C#中使用属性控件添加属性窗口
查看>>
Java 消息队列-Java并发编程 阻塞队列
查看>>
Web Service简介
查看>>