[TK] Terrible Prime
题目链接 T415418
这道题严格的时间限制比较令人头疼,似乎需要一些高级的算法,但实际上是,想要用点基础知识通过这道题需要两种算法:费马小定理 (见下函数Miller_rabin) 用于subtask1,另一种算法 (见下函数prim) 用于subtask2.两个subtask的范围限制给了我们这样一个机会.
关于费马小定理,参见 Oi-wiki .
string s[2]={"No","Yes"};
typedef long long ll;
ll m;
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
typedef pair<int,int> pii;
const int zhenli=0;
const int maxx=0x7f7f;
const int N=3000005;
int n;
ll a[N],ma=-1,b[N];
inline ll quick_mul(ll a,ll b,ll m) //快速乘
{
ll ans = 0;
a %= m;
b %= m;
while (b) {
if (b & 1) {
ans = (ans + a) % m;
}
a = (a + a) % m;
b >>= 1;
}
return ans;
}
ll quick_pow(ll a,ll b,ll m) //快速幂
{
ll res=1;
a%=m;
while(b)
{
if(b&1) res=quick_mul(res,a,m);
a=quick_mul(a,a,m);
b>>=1;
}
return res;
}
bool Miller_rabin(ll n,ll num)
{
if(n==2||n==3) return true;
if(n%2==0||n==1) return false;
srand((unsigned)time(NULL)); //为接下来a的随机取值用
ll d=n-1;
int s=0;
while(!(d&1)) s++,d>>=1;//若d的二进制的最后一位不是1,则说明d还是偶数
for(int i=0;i<num;i++)
{
ll a=rand()%(n-2)+2;//2~n-1;
ll x=quick_pow(a,d,n), y=0;
for(int j=0;j<s;j++)//一共平方s次
{
y=quick_mul(x,x,n);//先平方
if(y==1&&x!=1&&x!=(n-1)) return false;//验证二次探测原理
x=y;
}
if(y!=1) return false;//不满足费马小定理,那就肯定不是质数
}
return true;
}
bool prim(ll num)
{
if(num==1)return 0;
if(num==2||num==3)return 1;
if(num%6!=1&&num%6!=5)return 0;
long long tmp=sqrt(num);
for(long long i=6;i<=tmp+1;i+=6){
if(num%(i-1)==0||num%(i+1)==0)return 0;
}
return 1;
}
int main(){
ll n;
cin>>n;
if(n<=900){
fo(i,1,n)
{
scanf("%lld",&a[i]);
ma=max(ma,a[i]);
b[i]=10;
}
fo(i,1,n)
{
if(Miller_rabin(a[i],b[i]))cout<<"Yes";
else cout<<"No";
if(i!=n)cout<<endl;
}
return 0;
}
for(int i=1;i<=n;i++){
scanf("%lld",&m);
cout<<s[prim(m)]<<endl;
}
return 0;
}