Fansblog---威尔逊定理

Fansblog

题意:给一个质数\(p\),找小于\(p\)的最大质数\(q\),并求\(q!modp\). \(p,q\epsilon(10^9, 10^{14})\)

题解:威尔逊定理:一个数\(n\)若是质数, 则有 \((n - 1)! \equiv n - 1 mod n\). 于是可以先令\(ans = p - 1\), 再对\(p - 1\)\(q\)的数对\(p\)求逆元。\(p\)\(q\)之间的距离不会超过300,判定一个\(10^{14}\)级别的素数可以先用欧拉筛对\(10^{7}\)之内的素数打表(总共约\(6\times10^{6}\)个素数),这样每次可以用o(\(6\times10^{6}\))的时间判断这个数是不是素数。(感谢董队的__int128板子TUT)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef __int128 ll;
const int maxn = 1e7 + 5;
int prime[maxn];
int visit[maxn];
inline __int128 read(){
    __int128 x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

inline void print(__int128 x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
    putchar(x%10+'0');
}
void Prime(){
    for (int i = 2;i <= maxn; i++) {
        if (!visit[i]) {
            prime[++prime[0]] = i;
        }
        for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
            visit[i*prime[j]] = 1;
            if (i % prime[j] == 0) {
                break;
            }
        }
    }
}
int p[maxn], cnt;
ll qpow(ll x, ll y, ll mod) {
	ll base = x, res = 1;
	while(y) {
		if(y & 1) res = (res * base) % mod;
		base = (base * base) % mod;
		y >>= 1;
	}
	return res;
}
bool isprime(ll x) {
	for(int i = 1; i <= cnt; i++) {
		if(p[i] >= x) return true;
		if((x % p[i]) == 0) return false;
	}
	return true;
}
int main() {
	Prime();
	for(int i = 2; i < maxn; i++) if(!visit[i]) p[++cnt] = i;
	int T;
	cin >> T;
	while(T--) {
		ll n;
		//scanf("%I128d", &n);
		n = read();
		ll ans = n - 1;
		ll i = n - 1;
		while(1) {
			if(isprime(i)) {
				break;
			}
			ans = (ans * qpow(i, n - 2, n)) % n;
			i--;
		}
		print(ans);
		printf("\n");
	}
}
posted @ 2019-07-29 17:26  rain_star  阅读(317)  评论(0编辑  收藏  举报