foj 1649 Prime number or not

素性测试,用Miller-Rabin算法,今天才知道我之前米勒罗宾算法学的不对...刚纠正过来,顺便学了一个O(logn)的快速乘法,与O(logn)的快速幂原理一样,把一个数拆分成二进制,然后按位做乘法,在数特大的时候可以避免爆long long,另外还有一个做法是利用类型转换,long long 转double,进行运算,这个我就不太了解了(对double类型不感冒)

这是较好的Miller-Rabin学习资料http://www.matrix67.com/blog/archives/234,神Matrix67写的。

然后这张图是群里别人给的,根据这个选择底数个数,确保算法正确性。

 

下面是代码,用第一种二进制思想的快速乘法时间是500+ms,第二种类型转换思想实现的代码时间是46ms...

//Miller-Rabin素性测试 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxp 9
typedef long long llong;
int P[maxp]={2,3,5,7,11,13,17,19,23};
/*llong quickmul(llong a,llong b,llong n)
{
    llong ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%n;
        a=(a*2)%n;
        b>>=1;
    }
    return ans;
}*/
llong quickmul(llong a,llong b,llong n)
{
    llong c=(llong)((double)a*(double)b/(double)n);
    return (a*b+n-c*n)%n;
}
llong quickpow(llong a,llong b,llong n)
{
    llong ans=1;
    while(b)
    {
        if(b&1)
//            ans=(ans*a)%n;
            ans=quickmul(ans,a,n);
//        a=(a*a)%n;
        a=quickmul(a,a,n);
        b>>=1;
    }
    return ans;
}
bool Miller_Rabin(llong x)
{
    if(x==2)
        return true;
    if(x==1||x%2==0)
        return false;
    bool ans=true;
    llong d=x-1,t,p;
    int i;
    while(!(d&1))
        d>>=1;
    for(i=0;i<maxp&&P[i]<x;++i)
    {
        t=d;
        p=quickpow(P[i],t,x);
        while(t!=x-1&&p!=1&&p!=x-1)
        {
//            p=(p*p)%x;
            p=quickmul(p,p,x);
            t<<=1;
        }
        ans&=((p==x-1)||(t&1==1));
        if(ans==false)
            return ans;
    }
    return ans;
}
int main()
{
    llong x;
    while(scanf("%I64d",&x)!=EOF)
        if(Miller_Rabin(x))
            cout<<"It is a prime number."<<endl;
        else
            cout<<"It is not a prime number."<<endl;
    return 0;
}

 ps:调试代码发现个细节,位操作符的优先级很低,甚至比输入输出操作符都低,注意加括号,之前写成d&1==0,wa了好多次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值