由素数算数基本定理得 n 能拆分程 x个素数之积。
n的因子个数为(a1+1)(a2+1).。。。
已知p为质数,所以 如果n为p的奇异数,则一定满足 n开p-1次方 一定是一个素数。
所以 当p>3 时, 情况不多,打表就行。
p=3时, 直接对n开方,在判断是否是素数就行。
#include <bits/stdc++.h>
typedef long long LL;
const int maxn = 31623, maxm = 17, maxp = 61;//sqrt(10^9) , 60以内素数个数 , ln(10^18)
const LL maxv = (LL)1e18,maxq=(LL)1e9;
int tot, pr[maxn], d[maxn], sz[maxm];
LL pp[maxm][maxn];
bool isprime(int x){ //判素
if(x<2) return 0;
if(x<maxn) return d[x] == x;
for(int i=0;i<tot&&pr[i]*pr[i]<=x;++i)
if(x%pr[i]==0) return 0;
return 1;
}
int main(){
tot=0;
for(int i=2; i<maxn; ++i){//快速线性筛法求素数
if(!d[i])
pr[tot++] = d[i] = i;
for(int j=0,k;(k=i*pr[j])<maxn;++j){
d[k]=pr[j];
if(!(d[i]%pr[j]))
break;
}
}
for(int i=2;i<maxm;++i){//打表
for(int j=0;j<tot;++j){
int rem=pr[i]-1;
LL val=1,lim=maxv/pr[j];
for( ;rem&&val<=lim;--rem,val*=pr[j]);
if(rem) break;
pp[i][sz[i]++] = val;
}
}
int t;
LL n, p;
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&n,&p);
if(p>=maxp||d[p]!=p){
puts("NO");
continue;
}
if(p==3){
LL val=(LL)sqrt(n);
puts(val*val==n&&isprime(val)?"YES":"NO");
continue;
}
for(int i=2;i<maxm;++i)
if(pr[i]==p){
puts(*std::lower_bound(pp[i],pp[i]+sz[i],n)==n?"YES":"NO");
break;
}
}
return 0;
}
现场的代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=111;
const int S = 50;
int a[32222];
int main(){
a[0]=a[1]=1;
for(int i=2;i<32000;++i){
if(!a[i])
for(int j=i+i;j<32000;j+=i)
a[j]=1;
}
int T;
ll n,p;
scanf("%d",&T);
while(T--){
scanf("%lld %lld",&n,&p);
int cnt=0,f=0;
if(p==3) {
int ss=0;
int t=sqrt(n);
if(t*t==n) ss=1;
if(ss==1) printf("YES\n");
else printf("NO\n");
continue;
}
for(int i=2;i<32000;++i){
if(a[i]==0&&n%i==0) {
if(n==pow(i,p-1)) f=1;
break;
}
}
if(f) printf("YES\n");
else printf("NO\n");
}
return 0;
}