我们可以将数组开到 106 ,进行小素数的筛选。
#define M 1000005
bool mark[M];
int tot,D[M];
void init(){
for(int i=2;i<M;i++)
if(!mark[M]){
D[++tot]=i;
for(int j=i+i;j<M;j+=i)mark[i]=1;
}
}
因此随意来一个小于 1018 的数now。可以先用$10^6}的素数去筛。
#define ll long long
bool Small(ll now){
for(int i=1;i<=tot;i++)
if(now%D[i]==0)return true;
return false;
}
如果不成功,那么这个数本身就是一个大素数,或者它是由两个大素数组成。
然后我们采用Miller Rabin
ll Mul(ll x,ll y,ll mod){//计算x*y%mod
ll res=0;
if(x<y)swap(x,y);
while(y){
if(y&1){
res+=x;
if(res>=mod)res-=mod;
}
y>>=1;
x<<=1;
if(x>=mod)x-=mod;
}
return res;
}
ll Pow(ll x,ll y,ll mod){//计算x^y%mod
ll res=1;
while(y){
if(y&1)res=Mul(res,x,mod);
y>>=1;
x=Mul(x,x,mod);
}
return res;
}
bool check(ll u,ll t,ll now){
ll s=1ll*rand()*rand()%(now-2)+2;
s=Pow(s,u,now);
ll last=s;
for(ll i=1;i<=t;i++){
s=Mul(s,s,now);
if(s==1&&last!=1&&last!=now-1)return false;
last=s;
}
return s==1;
}
bool chk(ll now){
if(now<2)return false;
if(!(now&1))return now==2;
ll t=0,u=now-1;
while(!(u&1))u>>=1,t++;
for(int i=1;i<=10;i++)
if(!check(u,t,now))return false;
return true;
}