hihocoer 1287 数论一·Miller-Rabin质数测试

题目连接:点击打开链接
描述

小Hi和小Ho最近突然对密码学产生了兴趣,其中有个叫RSA的公钥密码算法。RSA算法的计算过程中,需要找一些很大的质数。

小Ho:要如何来找出足够大的质数呢?

小Hi:我倒是有一个想法,我们可以先随机一个特别大的初始奇数,然后检查它是不是质数,如果不是就找比它大2的数,一直重复,直到找到一个质数为止。

小Ho:这样好像可行,那我就这么办吧。

过了一会儿,小Ho拿来了一张写满数字的纸条。

小Ho:我用程序随机生成了一些初始数字,但是要求解它们是不是质数太花时间了。

小Hi:你是怎么做的啊?

说着小Hi接过了小Ho的纸条。

小Ho:比如说我要检测数字n是不是质数吧,我就从2开始枚举,一直到sqrt(n),看能否被n整除。

小Hi:那就对了。你看纸条上很多数字都是在15、16位左右,就算开方之后,也有7、8位的数字。对于这样大一个数字的循环,显然会很花费时间。

小Ho:那有什么更快速的方法么?

小Hi:当然有了,有一种叫做Miller-Rabin质数测试的算法,可以很快的判定一个大数是否是质数。

提示:Miller-Rabin质数测试

输入

第1行:1个正整数t,表示数字的个数,10≤t≤50

第2..t+1行:每行1个正整数,第i+1行表示正整数a[i],2≤a[i]≤10^18

输出

第1..t行:每行1个字符串,若a[i]为质数,第i行输出"Yes",否则输出"No"

样例输入
3
3
7
9
样例输出
Yes
Yes
No

AC代码(套用了kuangbin的模板)

PS:此处如果单纯的套快速幂板子会TLE,所以需要处理一下;

#include <bits/stdc++.h>
#define ll long long
using namespace std ;
const int S = 10 ;  //*判定次数
ll multmod(ll a , ll b , ll c)//*求(a*b)%c
{
    a%=c ;
    b%=c;
    ll res = 0 ;
    ll tmp = a ;
    while(b)
    {
        if(b&1)
        {
            res += tmp;
            if(res > c) res-=c;
        }
        tmp<<=1;
        if(tmp>c) tmp-=c;
        b>>=1;
    }
    return res;
}
ll quick(ll a , ll b , ll mod ) //*求(a^b)%mod
{
    ll ans = 1;
    ll temp = a%mod;
    while(b)
    {
        if(b&1) ans = multmod(ans,temp,mod);
        temp = multmod(temp,temp,mod);
        b>>=1;
    }
    return ans ;
}
bool check(ll a , ll b , ll x , ll t)
{
    ll ret = quick(a,x,b);
    ll last  = ret ;
    for(int i = 1 ; i<=t ; i++)
    {
        ret = multmod(ret,ret,b);
        if(ret==1&&last!=1&&last!=b-1) return true;
        last = ret ;
    }
    if(ret!=1) return true;
    else return false;
}
bool miller(ll n)
{
    if(n<2) return false;
    if(n==2) return true;
    if(n%2==0) return false;
    ll x = n - 1;
    ll t = 0 ;
    while(x%2==0) {x/=2 ; t++;}
    srand(time(NULL));
    for(int i = 0 ; i < S ; i++)
    {
        ll a = rand()%(n-1)+1;
        if(check(a,n,x,t)) return false;
    }
    return true;
}
int main()
{
        ll  n ;
        int t ;
        cin>>t;
        while(t--)
        {
        cin>>n;
        if(miller(n)) printf("Yes\n");
        else printf("No\n");
        }
    return 0 ;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kelisita

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值