题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6608
题目大意:给一个质数P (1e9≤p≤1e14),找比它小的最大质数Q,求Q! Module P
1.质数密度分布:质数分布的比较密,在p周围100内应该能遇到质数,所以q可以从大到小枚举
2.判断10^14 内数x是否为质数,只用提前筛出1^7 内质数看是否有x因子
3.威尔逊定理 (p−1)!≡−1(mod p) 当p是质数时 ,实际上就是 (p-1)! mod p =p-1 求Q! MOD P = (P-1)!/(P-1)/(P-2).../(Q+1) MOD P =(P-1)*INF(P-1)*INF(P-2)*...*(Q+1)MOD P
INF(x)为 x逆元
4.求逆元方法:①费马小定理 a*ap-2 ≡ 1 (mod p) 用快速幂求出ap-2即求出aa的逆元.
②扩展欧几里得 xa≡1 mod p 解 xa+yp=1
因为p太大,用费马小定理会超时,用扩展欧几里得求
ps:p太大,直接(p-1)*(p-2)时会超long long,用快速乘(把乘法分解为多次加法,一边加一边取模)
#include<bits/stdc++.h> using namespace std; //( p -1 )! ≡ -1 =p-1( mod p ) 当p为素数时 long long const n=1e7+100; typedef long long ll; ll prime[n]; ll p,q,cntprime,ans; bool flag[n]; void exgcd(ll a,ll b,ll &x,ll &y){//扩展欧几里得求逆元快一点,用费马小定理 a^(p-2) 由于p太大,容易超时 if(!b){x=1;y=0;} else {exgcd(b,a%b,y,x);y-=x*(a/b);} } ll getinv(ll a){//求q!%p 相当于= (p-1)!/(p-1)/(p-2)...(q+1)%p 用逆元 ll x,y; exgcd(a,p,x,y); while(x<0)x+=p; return x; } ll mul(ll a,ll b){//快速乘 防止longlong 相乘会炸longlong ll ret=0; for(;b;b>>=1,a=(a<<1)%p) if(b&1) ret=(ret+a)%p; return ret%p; } void getans(){ ans=p-1; for(ll i=p-1;i>q;i--){ ans=mul(getinv(i),ans);//用快速乘 } } void getprime(){//判断1e14内的质数,只需看有无1e7内的质数 cntprime=0; for (ll i = 2; i <= 1e7; i++) { if (!flag[i]) prime[++cntprime] = i; for (int j = 1; j <= cntprime && prime[j] * i <= n; j++) { flag[i * prime[j]] = true; if (i % prime[j] == 0) break; } } } void getq(){//素数密度分布,素数分布的比较密集 cout<<p-q<<endl; //可以从大到小枚举,判断是否为质数,出现的比较快 bool ok; for(ll i=p-2;i>=2;i--){ ok=false; ll z=(long long)sqrt(i); for(int j=1;j<=cntprime&&prime[j]<=z;j++)if(i%prime[j]==0){ok=true;break;} if(!ok){q=i;return ;} } } int main(){ int t; scanf("%d",&t); getprime(); while(t--){ scanf("%lld",&p); getq(); getans(); cout<<ans<<endl; } return 0; }
威尔逊定理证明:https://blog.csdn.net/qq_36056315/article/details/83054665
原文地址:https://www.cnblogs.com/conver/p/11273386.html
时间: 2024-10-21 00:30:22