描述
萌蛋在练习模n意义下的乘法时发现,总有一些数,在自乘若干次以后,会变成1。例如n=7,那么5×5 mod 7=4,4×5 mod 7=6,6×5 mod 7=2,2×5 mod 7=3,3×5 mod 7=1。如果继续乘下去,就会陷入循环当中。
萌蛋还发现,这个循环的长度经常会是φ(n),即小于n且与n互质的正整数的个数。例如,φ(7)=6,而上述循环的长度也是6,因为5,4,6,2,3,1共有6个数。
再如n=6,那么5×5 mod 6=1。这个循环的长度很短,只有2,而恰好φ(6)=2。
然而,对于某些情况,虽然循环的长度可以是φ(n),但存在比φ(n)更小的长度:例如n=7,而2×2 mod 7=4,4×2 mod 7=1,循环的长度只有3。当然,6也可以是一个循环的长度。
假设已知了n,我们称数a神奇的,当且仅当关于数a的循环长度可以是φ(n),而且不存在比φ(n)更小长度的循环。例如对于n=7,5是神奇的,而2不是神奇的。
现在给出n和q次询问,每次询问给出a,问a是否是神奇的。
输入格式
第一行两个整数n q。n≤10,000,000,q≤100,000,0≤a<n。
第二行有q个整数,每个表示一个a。
输出格式
输出q个字符,1表示这个数是神奇的,0表示这个数不是神奇的。
样例输入
7 3
5 2 0
样例输出
100
首先我们用O(sqrt(n))的时间求出fai(n),然后对于每一个数a,进行一次快速幂算出afai(n)Mod n是否为1,不为1则直接输出0即可。
题目中已经告知循环的长度必定为fai(n)的因数,那么我们事先用sqrt(n)的时间求出fai(n)的所有因数,那么一个数的因数是log(n)级别的,于是对于每一个因数进行快速幂判断是否神奇,总复杂度loglogn
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <set> 11 #include <list> 12 #include <vector> 13 #include <ctime> 14 #include <iterator> 15 #include <functional> 16 #define pritnf printf 17 #define scafn scanf 18 #define For(i,j,k) for(int i=(j);i<=(k);(i)++) 19 using namespace std; 20 typedef long long LL; 21 typedef unsigned int Uint; 22 const int INF=0x7ffffff; 23 //==============struct declaration============== 24 25 //==============var declaration================= 26 LL bound; 27 vector <LL> fact; 28 int siz; 29 //==============function declaration============ 30 int fai(LL x); 31 int gcd(LL a,LL b){return a%b==0?b:gcd(b,a%b);} 32 bool loop(LL x,LL Mod); 33 void divide(LL x); 34 LL quickpow(int x,int Exp,LL Mod); 35 //==============main code======================= 36 int main() 37 { 38 LL Mod,q; 39 scanf("%lld%lld",&Mod,&q); 40 bound=fai(Mod);divide(bound); 41 while (q--){ 42 LL query; 43 scanf("%lld",&query); 44 if (gcd(query,Mod)!=1)//可以证明如果不互质是不可能循环的 45 //此处用quickpow亦可,时间复杂度均为log(n) 46 putchar('0'); 47 else if (loop(query,Mod)) 48 putchar('1'); 49 else 50 putchar('0'); 51 } 52 return 0; 53 } 54 //================fuction code==================== 55 int fai(LL x)//欧拉函数 56 { 57 LL res=x; 58 LL m=sqrt(x+0.5); 59 for(LL i=2;i<=m;i++){ 60 if (x%i==0){ 61 res=res/i*(i-1); 62 while (x%i==0) 63 x/=i; 64 } 65 } 66 if (x!=1) 67 res=res/x*(x-1); 68 return res; 69 } 70 bool loop(LL x,LL Mod)//判断是否神奇 71 { 72 for(int i=0;i<=siz;i++) 73 if (quickpow(x,fact[i],Mod)==1) 74 return false; 75 return true; 76 } 77 void divide(LL x)//分解因数 78 { 79 int m=sqrt(x+0.5); 80 For(i,2,m) 81 if (x%i==0){ 82 fact.push_back(i); 83 fact.push_back(x/i); 84 } 85 sort(fact.begin(),fact.end()); 86 siz=fact.size()-1; 87 } 88 LL quickpow(int x,int Exp,LL Mod)//快速幂 89 { 90 if (Exp==0) 91 return 1; 92 if (Exp==1) 93 return x; 94 LL t=quickpow(x,Exp/2,Mod); 95 t=(t*t)%Mod; 96 if (Exp&1) 97 t=(t*x)%Mod; 98 return t; 99 }