poj 1811 Pallor Rho +Miller Rabin

/*
题目:给出一个数 如果是prime 输出prime 否则输出他的最小质因子
Miller Rabin +Poller Rho 大素数判定+大数找质因子
后面这个算法嘛 基于Birthday Paradox 
简单点说就是 在 1到100 内去一个数 ai ai==42的概率很小
但是如果取两个数 ai bi ai-bi==42 的概率就会变大
应用到找素因子上 就不用像试除法那样一个一个的试
但是如果枚举ai bi 显然也很slow 那么有一个非常好使(奇怪)的函数 
f(x)=x*x+c 这样将x和f(x)%p作为两个数 看看x-f(x) 与p的关系 
这里我们不是试试 p%(x-f(x))==0来找 而是 gcd一下 d=(p,(x-f(x))) 
d显然是p的因子 然后分解d 这样就ok了 
 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#define ll long long
using namespace std;
ll T,ans[110],tot;
ll init()
{
    ll x=0;char s;s=getchar();
    while(s<'0'||s>'9')s=getchar();
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x;
}
ll gcd(ll a,ll b)
{
    return !b?a:gcd(b,a%b);
}
ll slow_mul(ll a,ll b,ll c)//防止爆掉 
{
    a=a%c;b=b%c;
    ll an=0;
    while(b)
      {
          if(b&1)
            {
                b--;
                an=an+a;
                an=an%c;
          }
        a<<=1;a=a%c;b>>=1;
      }
    return an;
}
ll Mi(ll a,ll m,ll p)
{
    if(m==0)return 1;
    ll x=Mi(a,m/2,p)%p;
    x=slow_mul(x,x,p);
    if(m&1)x=slow_mul(x,a,p);
    return x;
}
ll Pollard_rho(ll p,ll c)
{
    ll i=1,k=2;
    ll x=rand()%(p-1)+1;
    ll fx=x;
    while(1)
      {
          i++;
        x=(slow_mul(x,x,p)+c)%p;
          ll g=gcd(fx-x+p,p);//防止fx-x<0 
          if(g!=1&&g!=p)return g;//找到一个因子 
          if(x==fx)return p;//进入环 换一个随机数  
          if(i==k)
            {
                k=k+k;
                fx=x;
          }
      }
}
bool Miller_Rabin(ll n)
{
    if(n==2)return 1;
    if(n==1||!(n&1))return 0;
    ll m=n-1,j=0;
    while(!(m&1)) 
      {
          j++;
          m=m>>1;
      }
    //srand(unsigned(time(0)));丫丫的poj用srand会RE 我看了好久0.0 
    for(int i=1;i<=10;i++)
      {
          ll a=rand()%(n-1)+1;
          ll x=Mi(a,m,n);
          for(int k=1;k<=j;k++)
            {
                ll y=slow_mul(x,x,n);
                if(y==1&&x!=1&&x!=n-1)return 0;
                x=y;
          }
        if(x!=1)return 0;
      }
    return 1;
}
void findpri(ll n)//质因数分解n 
{
    if(n<=1)return;
    if(Miller_Rabin(n))
      {
          ans[++tot]=n;
          return ;
      }
    ll p=n;
    while(p==n)//可能生成的随机数不合适  
      p=Pollard_rho(p,rand()%(n-1)+1);//返回n的一个因子 
    findpri(p);
    findpri(n/p);
}
int main()
{
    T=init();
    while(T--)
      {
          ll n=init();
          if(Miller_Rabin(n))//素数先来个判断 
            {
                printf("Prime
");
                continue;
          }
          memset(ans,0,sizeof(ans));//所有质因子 
          tot=0;
          findpri(n);//找质因子 
          ll an=ans[1];
          for(int i=1;i<=tot;i++)
            an=min(an,ans[i]);
          printf("%lld
",an);
      }
    return 0;
}
原文地址:https://www.cnblogs.com/yanlifneg/p/5523424.html