Fansblog(杭电多校第三场F题) 威尔逊定理+素数间隔

**

Fansblog(杭电多校第三场F题)

**
题目描述:
Farmer John keeps a website called ‘FansBlog’ .Everyday , there are many people visited this blog.One day, he find the visits has reached P , which is a prime number.He thinks it is a interesting fact.And he remembers that the visits had reached another prime number.He try to find out the largest prime number Q ( Q < P ) ,and get the answer of Q! Module P.But he is too busy to find out the answer. So he ask you for help. ( Q! is the product of all positive integers less than or equal to n: n! = n * (n-1) * (n-2) * (n-3) *… * 3 * 2 * 1 . For example, 4! = 4 * 3 * 2 * 1 = 24 )
输入:
First line contains an number T(1<=T<=10) indicating the number of testcases.
Then T line follows, each contains a positive prime number P (1e9≤p≤1e14)
输出:
For each testcase, output an integer representing the factorial of Q modulo P.
样例输入:
1
1000000007
样例输出:
328400734
题目大意:
给一个正整数素数p,求一个小于p的最大正整数素数q,输出 q的阶乘%p的结果(有多组输入)。
心路历程及题解:
前面看错题的丢人事就不说了,就从真正理解题意开始说起吧。。。求素数,我们一开始想的是用欧拉筛暴力打表,再把表暴力打进数组里,最后发现1e14的数据程序跑不出来。。。只能用了一个真.暴力解法(从p开始一个一个往前推,每个数跑1e7的数据,如果被卡掉就说明不是素数),当然这个做法比较玄学,只能说数据正好符合了吧。之后,我们采用了逆元的解法(逆元:a,p互质,则a/p=a**a^(p-2),这个怎么用的在文尾图中说明),又发现数据太大,long long都装不下,只好用了大数乘法(不是高精度)。。。这中间还有一个规律,p和q如果是孪生素数,结果是-1,当然对这题用处不大,最后把它去掉跑的时间一样。还是两个队友太强,我最后就是看懂他们的代码改了个bug。。。orz
AC代码:

#include <iostream>
#include <time.h>
#include <fstream>
using namespace std;
typedef unsigned long long ll;
ll mul(ll a,ll b,ll mod)//大数乘法,其实和快速幂就只有两处改动,已在下面标出
{
    a%=mod;
    b%=mod;
    ll sum=0;
    while(b)
    {
        if(b&1)
        {
            sum=(sum+a)%mod;//001,将*改为+
        }
        b>>=1;
        a=a*2%mod;//002,将*a改为*2
    }
    sum%=mod;
    return sum;
}
ll qmod(ll a,ll b,ll mod)//快速幂
{
    ll sum=1;
    while(b)
    {
        if(b&1)
        {
            sum=mul(sum,a,mod);
        }
        b>>=1;
        a=mul(a,a,mod);
    }
    return sum;
}
ll getfac(ll s,ll e,ll mod)//这个是求分母,分母是什么文尾图片解释
{
    ll f=1;
    for(ll i=s+1; i<=e-2; i++)
    {
        f=mul(f,i,mod);
    }
    f%=mod;
    return f;
}
bool judge(ll n)//判断素数
{
    for(ll i=2; i<=10000000; i++)
    {
        if(n%i==0)
            return false;
    }
    return true;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        ll n;
        cin>>n;
        ll p;
        for(p=n-1; p; p--)
        {
            if(judge(p))
                break;
        }
        if(p==n-2)//特判,要不要都行
        {
            cout<<1<<endl;
            continue;
        }
        ll fac=getfac(p,n,n);
        ll ans=qmod(fac,n-2,n)%n;//求逆元
        cout<<ans<<endl;
    }
    return 0;
}

作者:suol,明灵
来源:CSDN
原文:https://blog.csdn.net/soul_mingling/article/details/97751852

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值