HDU -- 2138 How many prime numbers + hihocoder 1287【大素数判定】

来源:互联网 发布:淘宝如何加入村淘 编辑:程序博客网 时间:2024/06/17 04:25

先来板子: (判断大(小)素数都可以用这个板子)

/** @Cain*/const int S = 20;inline ll mult_mod(ll a, ll b, ll m){    ll c = a*b-(ll)((long double)a*b/m+0.5)*m;    return c<0 ? c+m : c;}ll pow_mod(ll a,ll b,ll m){    ll res = 1;    while (b)    {        if (b & 1) res = mult_mod(res, a, m);        a = mult_mod(a, a, m);        b >>= 1;    }    return res;}bool miller_rabin(ll n){    if (!(n&1)) return n == 2;    ll u=n-1,t=0;    while(u%2==0) u/=2,++t;    for (int i = 0; i < S; ++i){        ll a = rand()%(n-2)+2;        ll x = pow_mod(a, u, n);        for (ll j = 0; j < t ; j++){            ll y = mult_mod(x, x, n);            if( y == 1 && x != n-1 && x != 1)                return false;            x = y;        }        if (x != 1) return false;    }    return true;}void solve(){    srand(time(0));    int t;    while(~scanf("%d",&t)){        int ans=0;        for(int i=1;i<=t;i++){            ll x; cin >> x;            if(miller_rabin(x)) ans++;        }        cout<<ans<<endl;    }}

解释版:

/** @Cain*/const int S = 20;//计算 (a*b)%m.inline ll mult_mod(ll a, ll b, ll m){    ll c = a*b-(ll)((long double)a*b/m+0.5)*m;    //(x/m)*m就是求距离x最近且是m的倍数的数是多少.    //相当于x-x%m,但前面这个可以保证精度.    return c<0 ? c+m : c;}//计算  a^b % m.ll pow_mod(ll a,ll b,ll m){    ll res = 1;    while (b)    {        if (b & 1) res = mult_mod(res, a, m);        a = mult_mod(a, a, m);        b >>= 1;    }    return res;}//米氏筛法bool miller_rabin(ll n){    if (!(n&1)) return n == 2;    ll u=n-1,t=0;    while(u%2==0) u/=2,++t;    for (int i = 0; i < S; ++i){        ll a = rand()%(n-2)+2;        ll x = pow_mod(a, u, n);        for (ll j = 0; j < t ; j++){            ll y = mult_mod(x, x, n);            // 依次检查每一个相邻的 a^u, a^2u, a^4u, ... a^(2^k*u)是否满足二次探测定理            //在满足u是奇数的时候x==1,且u是偶数时y==1 || y == n-1.            //既是下面这条判断语句.            if( y == 1 && x != n-1 && x != 1)                return false;            x = y;        }        if (x != 1) return false;    }    return true;}void solve(){    srand(time(0));    int t;    while(~scanf("%d",&t)){        int ans=0;        for(int i=1;i<=t;i++){            ll x; cin >> x;            if(miller_rabin(x)) ans++;        }        cout<<ans<<endl;    }}

传送门
//思路: 大素数判定的原理是费马小定理
费马小定理:
a为整数,p是素数,且a,p互质,则有a^(p-1)≡1(mod p) ,即:a^(p-1)模p得1.

快速判定一个数是否为素数的方法:
如果存在一个整数a,使得a^(p-1)≡1(mod p) ,则称p为基于a的伪素数,当有多个满足关系的a时,则p为素数的概率趋向于1。所以取多个a测试一下即可. (感觉随机, 错误概率还是较小.)

AC Code

/** @Cain*/const int S = 20;inline ll mult_mod(ll a, ll b, ll m){    ll c = a*b-(ll)((long double)a*b/m+0.5)*m;    return c<0 ? c+m : c;}ll pow_mod(ll a,ll b,ll m){    ll res = 1;    while (b)    {        if (b & 1) res = mult_mod(res, a, m);        a = mult_mod(a, a, m);        b >>= 1;    }    return res;}bool miller_rabin(ll n){    if (!(n&1)) return n == 2;    ll u=n-1,t=0;    while(u%2==0) u/=2,++t;    for (int i = 0; i < S; ++i){        ll a = rand()%(n-2)+2;        ll x = pow_mod(a, u, n);        for (ll j = 0; j < t ; j++){            ll y = mult_mod(x, x, n);            if( y == 1 && x != n-1 && x != 1)                return false;            x = y;        }        if (x != 1) return false;    }    return true;}void solve(){    srand(time(0));    int t;    while(~scanf("%d",&t)){        int ans=0;        for(int i=1;i<=t;i++){            ll x; cin >> x;            if(miller_rabin(x)) ans++;        }        cout<<ans<<endl;    }}

hihocoder – 1287
//上面那道数据都比较小, 如果想测板子, 还是测测这道题把, 非常的卡人.!!!!!
AC Code

/** @Cain*/const int S = 20;inline ll mult_mod(ll a, ll b, ll m){    ll c = a*b-(ll)((long double)a*b/m+0.5)*m;    return c<0 ? c+m : c;}ll pow_mod(ll a,ll b,ll m){    ll res = 1;    while (b)    {        if (b & 1) res = mult_mod(res, a, m);        a = mult_mod(a, a, m);        b >>= 1;    }    return res;}bool miller_rabin(ll n){    if (!(n&1)) return n == 2;    ll u=n-1,t=0;    while(u%2==0) u/=2,++t;    for (int i = 0; i < S; ++i){        ll a = rand()%(n-2)+2;        ll x = pow_mod(a, u, n);        for (ll j = 0; j < t ; j++){            ll y = mult_mod(x, x, n);            if( y == 1 && x != n-1 && x != 1)                return false;            x = y;        }        if (x != 1) return false;    }    return true;}void solve(){    srand(time(0));    int t;    while(~scanf("%d",&t)){        for(int i=1;i<=t;i++){            ll x; cin >> x;            if(miller_rabin(x)) puts("Yes");            else puts("No");        }    }}