Fansblog

Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1850    Accepted Submission(s): 747


Problem Description

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 )

 Input

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)

 Output

For each testcase, output an integer representing the factorial of Q modulo P.

 Sample Input

1 1000000007

 Sample Output

328400734


题目大意:找一个比P小的一个质数,求 Q!mod P 的值.

题目思路:思路就不说了,直到威尔逊定理之后就完全可以了.简要分享一下收货:

1.根据证明(记住就可以了),1e18之内的两个相邻的素数不会超过264

2.威尔逊定理:(P-1)!同余-1模 P,(P-2)!同余 P 模 1 ,所以就有 (P-2)! (mod p) = 1.所以(Q!(Q+1)!(Q+2)!(Q+3)!(Q+4)!.....(P-2)!)%p=1

所以 Q!=1/(Q+1)!(Q+2)!(Q+3)!(Q+4)!.....(P-2)!)%p,所以求一个逆元就好了.

3.如果数值太大,快速幂过程中 会爆long long ,应该在 快速幂过程中 加一个快速× 取余

附上AC代码:这个题直接 暴力 判断素数也能过:(因为他超不过264)

#include <bits/stdc++.h>
#define E 2.718
using namespace std;
typedef long long ll;
const ll INF=1e9+5;
const int maxn=2e6+8;
const double eps=1e-10;
ll prime[6] = {2, 3, 5, 233, 331};
ll n,m,a,b,c;
ll qmul(ll a,ll b,ll mod)
{
    ll ans=0;
    while(b)
    {
        if(b&1) ans=(ans+a)%mod;
        a=(a+a)%mod;b/=2;
    }
    return ans;
}
ll qpow(ll a,ll b,ll mod)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=qmul(ans,a,mod);
        b=b>>1;a=qmul(a,a,mod);
    }
    return ans;
}

bool Miller_Rabin(ll p) {
    if(p < 2) return 0;
    if(p != 2 && p % 2 == 0) return 0;
    ll s = p - 1;
    while(! (s & 1)) s >>= 1;
    for(int i = 0; i < 5; ++i) {
        if(p == prime[i]) return 1;
        ll t = s, m = qpow(prime[i], s, p);
        while(t != p - 1 && m != 1 && m != p - 1) {
            m = qmul(m, m, p);
            t <<= 1;
        }
        if(m != p - 1 && !(t & 1)) return 0;
    }
    return 1;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%lld",&n);
        ll temp=n-1;
        while(!Miller_Rabin(temp)) temp--;
        ll res=1;
        for(ll i=temp+1;i<=n-2;i++)
            res=qmul(res,i,n);
        printf("%lld\n",qpow(res,n-2,n));
    }
    return 0;
}

总结:要多去学学关于素数的定理了!