bzoj3667: Rabin-Miller算法

来源:互联网 发布:俄罗斯民族性格 知乎 编辑:程序博客网 时间:2024/06/06 01:01

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=3667

题解

  OI生涯中第一次在bzoj上用题目刷屏。
  这道题是Pollard rho裸题,但是:取模会TLE!
  写慢速乘的时候,我一开始用了取模,就T飞了,改成while(x>p)x-=p之后,只跑30s
  这充分证明了取模是多么多么慢。

代码

//Pollard Rho#include <cstdio>#include <algorithm>#include <map>#include <cstdlib>#define ll long longusing namespace std;ll ans;inline ll md(ll x, ll p){while(x>p)x-=p;return x;}inline ll mult(ll a, ll b, ll p){    ll ans=0, t=a;    for(;b;b>>=1,t=md(t+t,p))if(b&1)ans=md(ans+t,p);    return ans;}inline ll pow(ll a, ll b, ll p){    ll ans=1, t=a;    for(;b;b>>=1,t=mult(t,t,p))if(b&1)ans=mult(ans,t,p);    return ans;}inline bool MR(ll n){    ll a, t, u, i, x, y;    if(n==2)return true;    if(~n&1)return false;    if(n==3 or n==5)return true;    if(n%3==0 or n%5==0)return false;    for(t=0,u=n-1;~u&1;u>>=1,t++);    for(ll tim=20;tim;tim--)    {        a=rand()%(n-1)+1;        for(y=x=pow(a,u,n),i=1;i<=t;i++)        {            x=mult(x,x,n);            if(x==1 and y!=n-1 and y!=1)return false;            y=x;        }        if(x!=1)return false;    }    return true;}ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}inline ll pollard_rho(ll n, ll c){    ll i, k, x=rand()%n, y=x, d;    for(i=1,k=2;;i++)    {        x=(mult(x,x,n)+c)%n;        d=gcd(y>x?y-x:x-y,n);        if(d>1 and d<n)return d;        if(x==y)return n;        if(i==k)y=x,k<<=1;    }}void find(ll n, ll c){    if(n==1 or n<ans)return;    if(MR(n)){ans=max(ans,n);return;}    ll p=pollard_rho(n,c);    for(;p==n;p=pollard_rho(n,++c));    find(max(p,n/p),c), find(min(p,n/p),c);}int main(){    ll T, n;    srand(12345);    for(scanf("%lld",&T);T;T--)    {        scanf("%lld",&n);        ans=0;        find(n,1);        if(ans==n)printf("Prime\n");else printf("%lld\n",ans);    }    return 0;}
0 0