hdu 6608 威尔逊定理+快速测素数法

前言:

这题我不会,我是真的不会,数论一窍不通,我只负责记住结论

Fansblog _题目链接

快速测素数法:

我把代码改成我喜欢用的模式
quick_prime()由三部分组成
一开始定义要测的素数
ll prime[10]= {2,3,5,7,11,13,17,19,23,29};
第一部分
ll quick_mul(ll a,ll b,ll mod)  //快速积
{
    long long ans=0,res=a;
    while(b)
    {
        if(b&1)
            ans=(ans+res)%mod;
        res=(res+res)%mod;
        b>>=1;
    }
    return (ll)ans;
}
第二部分
ll quick_mi(ll a,ll b,ll mod)     //快速幂
{
    ll ans=1,res=a;
    while(b)
    {
        if(b&1)
            ans=quick_mul(ans,res,mod);
        res=quick_mul(res,res,mod);
        b>>=1;
    }
    return ans;
}
第三部分
bool quick_prime(ll x)     //快速判断素数
{
    ll i,j,k;
    ll s=0,t=x-1;
    if(x==2)  return true;   //2是素数
    if(x<2||!(x&1))  return false;     //如果x是偶数或者是0,1,那它不是素数
    while(!(t&1))  //将x分解成(2^s)*t的样子
    {
        s++;
        t>>=1;
    }
    for(i=0; i<10&&prime[i]<x; ++i)    //随便选一个素数进行测试
    {
        ll a=prime[i];
        ll b=quick_mi(a,t,x);      //先算出a^t
        for(j=1; j<=s; ++j)  //然后进行s次平方
        {
            k=quick_mul(b,b,x);   //求b的平方
            if(k==1&&b!=1&&b!=x-1)     //用二次探测判断
                return false;
            b=k;
        }
        if(b!=1)  return false;   //用费马小定律判断
    }
    return true;   //如果进行多次测试都是对的,那么x就很有可能是素数
}

威尔逊定理:

p 为质数⟺(p−1)!≡−1(mod p)

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
ll prime[10]= {2,3,5,7,11,13,17,19,23,29};
ll quick_mul(ll a,ll b,ll mod)  //快速积(和快速幂差不多)
{
    long long ans=0,res=a;
    while(b)
    {
        if(b&1)
            ans=(ans+res)%mod;
        res=(res+res)%mod;
        b>>=1;
    }
    return (ll)ans;
}
ll quick_mi(ll a,ll b,ll mod)     //快速幂,这里就不赘述了
{
    ll ans=1,res=a;
    while(b)
    {
        if(b&1)
            ans=quick_mul(ans,res,mod);
        res=quick_mul(res,res,mod);
        b>>=1;
    }
    return ans;
}
bool quick_prime(ll x)     //判断素数
{
    ll i,j,k;
    ll s=0,t=x-1;
    if(x==2)  return true;   //2是素数
    if(x<2||!(x&1))  return false;     //如果x是偶数或者是0,1,那它不是素数
    while(!(t&1))  //将x分解成(2^s)*t的样子
    {
        s++;
        t>>=1;
    }
    for(i=0; i<10&&prime[i]<x; ++i)    //随便选一个素数进行测试
    {
        ll a=prime[i];
        ll b=quick_mi(a,t,x);      //先算出a^t
        for(j=1; j<=s; ++j)  //然后进行s次平方
        {
            k=quick_mul(b,b,x);   //求b的平方
            if(k==1&&b!=1&&b!=x-1)     //用二次探测判断
                return false;
            b=k;
        }
        if(b!=1)  return false;   //用费马小定律判断
    }
    return true;   //如果进行多次测试都是对的,那么x就很有可能是素数
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll p;
        scanf("%lld",&p);
        ll Q=p-1;

        while(!quick_prime(Q))//快速求得素数Q
        {
            Q--;
        }
        //printf("%lld\n", Q);
        ll ans=p-1;
        for (ll i = p - 1; i > Q; --i)
            ans = quick_mul(ans, quick_mi(i, p - 2, p), p);
        printf("%lld\n",ans);
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值