# 存一波Miller-Rabin板子 多校第三场Fansblog

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 )

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long prime[10]={2,3,5,7,11,13,17,19,23,29};
long long Quick_Multiply(long long a,long long b,long long c) //快速积
{
long long ans=0,res=a;
while(b)
{
if(b&1)
ans=(ans+res)%c;
res=(res+res)%c;
b>>=1;
}
return (long long)ans;
}
long long Quick_Power(long long a,long long b,long long c)
{
long long ans=1,res=a;
while(b)
{
if(b&1)
ans=Quick_Multiply(ans,res,c);
res=Quick_Multiply(res,res,c);
b>>=1;
}
return ans;
}
bool Miller_Rabin(long long x) //判断素数
{
long long i,j,k;
long long 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) //随便选一个素数进行测试
{
long long a=prime[i];
long long b=Quick_Power(a,t,x); //先算出a^t
for(j=1;j<=s;++j) //然后进行s次平方
{
k=Quick_Multiply(b,b,x); //求b的平方
if(k==1&&b!=1&&b!=x-1) //用二次探测判断
return false;
b=k;
}
if(b!=1) return false; //用费马小定律判断
}
return true; //如果进行多次测试都是对的，那么x就很有可能是素数
}
long long ex_gcd(long long a,long long b,long long &x,long long &y)
{
if(b==0){x = 1;y = 0;return a;}
long long ans = ex_gcd(b,a%b,x,y);
long long temp = x;
x = y;
y = temp - a/b*y;
return ans;
}
long long inv(long long a,long long b)
{
long long x,y;
long long ans = ex_gcd(a,b,x,y);
if(ans!=1)return -1;
if(x<0)x = (x%b + b)%b;
return x;
}
__int128 aa, ab, am;
long long sb(long long a, long long b, long long m) {
aa = a, ab = b, am = m;
return (long long)(aa * ab % am);
}
int main()
{
long long p;
long long T;
scanf("%lld",&T);
while(T--)
{
long long ans=1;
scanf("%lld",&p);
for(long long i=p-1;;i--)
{

if(Miller_Rabin(i))break;
ans=sb(ans,inv(i,p),p);
}
printf("%lld\n",p-ans);
}
return 0;
}

posted @ 2019-07-29 21:05  xuzc  阅读(129)  评论(0编辑  收藏  举报