题目链接:https://vjudge.net/problem/HDU-6608
题意:找到小于素数p的最大素数Q,求Q!
题解:威尔逊定理:p为素数时:( p -1 )! ≡ -1 ( mod p ),1e18内两素数之间的差距也就几百,直接除去Q到q内的数即可,注意要用到快速乘,因为两个数相乘会超long long
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long ll;
ll ksc(ll x, ll y, ll mod) {
ll res = 0;
while(y) {
if(y & 1) res = (res + x) % mod;
y >>= 1;
x = (x + x) % mod;
}
return res;
}
ll ksm(ll x, ll y, ll mod) {
ll res = 1;
while(y) {
if(y & 1) res = ksc(res, x, mod) ;
y >>= 1;
x = ksc(x, x, mod);
}
return res;
}
long long m;
int prime[2000007], len;
bool ok[10000007];
void init() {
for(int i = 2; i <= 10000000; i++) {
if(ok[i] == 0) {
prime[len++] = i;
}
for(int j = 0; j < len && (ll)prime[j] * i <= 10000000; j++) {
ok[prime[j] * i] = 1;
if(i % prime[j] == 0) break;
}
}
}
bool judge(ll x) {
for(int i = 0; i < len && (ll) prime[i] * prime[i] <= x; i++) {
if(x % prime[i] == 0) return 0;
}
return 1;
}
int main()
{
init();
long long t,n,cnt;
long long k;
scanf("%lld", &t);
ll ans=1;
while(t--)
{
scanf("%lld", &n);
ans = n - 1;
for(long long i = n - 1; i; i--) {
if(judge(i)) {
m = i;
break;
}
ans = ksc(ans , ksm(i, n - 2, n) , n) % n;
}
printf("%lld\n", ans);
}
return 0;
}