poj 1811 Prime Test——miller rabin+pollard rho

被这道题虐了两天了……自己也试着敲了一下。。事实证明手上的模版不给力啊。。。先用手上的模版敲了一个miller rabin,结果9都给我判成素数,真是无言了,然后又用算导上面讲得方法自己敲了一个pollard rho,结果卡死了……只有少数几种情况会出答案,大部分情况都是卡死了。。悲剧一个。。后来去找解体报告,因为这个题本来就是模版题嘛。。大多数写的都不是很符合我的习惯,看不进去,好不容易找到两个我看得进去的吧,自己在hust上交了一下,居然RE了。。话说这种解题报告还交上来嘛。。。好不容易在百度知道上面找到了一份代码,我觉得写得挺不错的,也解决了一些我遇到的困惑。

素数判断用miller法 分解用pollard法 关键有几点

1:用2分法作64位乘法必须用unsigned __Int64 否则位移的时候会带符号(符号位移不掉)

2:pollard会陷入死循环 所以要加卡时 如果超过多少次还没出来就return 1,换个初始数继续

3:所有<<号,>>号必须全部加括号 像b1=(x<<32)>>32这种等号后面没加括号的是错误的 应该是b1=((x<<32)>>32);

4:发现pollard算法中用x*x-1产生随机数,如果那个-1改成其他数 效率会不一样 根据frkstyc大牛的代码 x*x+16381要将近快一倍(可是这位仁兄用的是10007。。。我自己换别的数字试了一下,确实没有更快的)

a27400 1811 Accepted 412K 375MS G++ 1872B 2011-09-02 17:07:07
//写得太好了,每一个函数都是一个模版呀~~~~
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>
#define gcc 10007
#define MAX ((INT)1<<63)-1

using namespace std;

typedef unsigned
long long INT;
INT p[
10]={2,3,5,7,11,13,17,19,23,29};
inline INT gcd(INT a,INT b)
{
INT m
=1;
if(!b) return a;
while(m)
{
m
=a%b;
a
=b;
b
=m;
}
return a;
}

//计算a*b%n

inline INT multi_mod(INT a,INT b,INT mod)
{
INT sum
=0;
while(b)
{
if(b&1) sum=(sum+a)%mod;
a
=(a+a)%mod;
b
>>=1;
}
return sum;
}

//计算a^b%n;

inline INT quickmod(INT a,INT b,INT mod)
{
INT sum
=1;
while(b)
{
if(b&1) sum=multi_mod(sum,a,mod);
a
=multi_mod(a,a,mod);
b
>>=1;
}
return sum;
}

bool miller_rabin(INT n)
{
int i,j,k=0;
INT u,m,buf;
//将n分解为m*2^k
if(n==2)
return true;
if(n<2||!(n&1))
return false;
m
=n-1;
while(!(m&1))
k
++,m>>=1;
for(i=0;i<9;i++)
{
if(p[i]>=n)
return true;
u
=quickmod(p[i],m,n);
if(u==1)
continue;
for(j=0;j<k;j++)
{
buf
=multi_mod(u,u,n);
if(buf==1&&u!=1&&u!=n-1)
return false;
u
=buf;
}
//如果p[i]^(n-1)%n!=1那么n为合数
if(u-1)
return false;
}
return true;
}

//寻找n的一个因子,该因子并不一定是最小的,所以下面要二分查找最小的那个因子
INT pollard(INT n)
{
INT i
=1;
INT x
=rand()%(n-1)+1;
INT y
=x;
INT k
=2;
INT d;
do
{
i
++;
d
=gcd(n+y-x,n);
if(d>1&&d<n)
return d;
if(i==k)
y
=x,k*=2;
x
=(multi_mod(x,x,n)+n-gcc)%n;
}
while(y!=x);
return n;
}

INT MIN;

INT pollard_min(INT n)
{
INT p,a,b
=MAX;
if(n==1) return MAX;
if(miller_rabin(n)) return n;
p
=pollard(n);
a
=pollard_min(p);//二分查找
INT y=n/p;
b
=pollard_min(y);
return a<b?a:b;
}

int main(void)
{
INT T;
INT n;
scanf(
"%lld",&T);
while(T--)
{
scanf(
"%lld",&n);
MIN
=MAX;
if(miller_rabin(n))
{
puts(
"Prime");
}
else printf("%lld\n",pollard_min(n));
}
return 0;
}

  

posted @ 2011-09-02 17:39  ω 提拉米兔 ℃  阅读(552)  评论(0编辑  收藏  举报