Problem about GCD
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 470 Accepted Submission(s):
77
Problem Description
Given integer m. Find multiplication of all
1<=a<=m such gcd(a, m)=1 (coprime with m) modulo m.
Input
Input contains multiple tests, one test per
line.
Last line contains -1, it should be skipped.
[Technical Specification]
m <= 10^18
Last line contains -1, it should be skipped.
[Technical Specification]
m <= 10^18
Output
For each test please output result. One case per line.
Less than 160 test cases.
Sample Input
1
2
3
4
5
-1
Sample Output
0
1
2
3
4
Source
打表找规律:
数字n 如果由 x^k组成 或者 2*y^k 组成(x,y不等于2了,k为1,2,3,....) 则结果为n-1;
否则为1.
思路:
1.特判%4的情况。
2.m = n , 如果m为偶数先除2 。
3.如果m本身就是素数 m = m^1 ,那就是n-1了。
4.如果m由两个素数组成 m = x*x ,x是素数. 也简单,开平方,然后判断是不是素数。
5.如果m由多个素数组成 m = x^k,那么这个素数一定在10^6里面出现。
至少为3次吧。
代码很挫。
1 #include<iostream> 2 #include<stdio.h> 3 #include<cstring> 4 #include<stdlib.h> 5 #include<time.h> 6 #include<math.h> 7 using namespace std; 8 typedef __int64 LL; 9 const int maxn = 1e6+1; 10 int prime[maxn],len; 11 bool s[maxn]; 12 13 void init() 14 { 15 int i,j; 16 len = 0; 17 memset(s,true,sizeof(s)); 18 s[1] = false; 19 for(i=2;i<maxn;i++) 20 { 21 if(s[i] == false) continue; 22 prime[++len] = i; 23 for(j=i*2;j<maxn;j=j+i) 24 s[j] = false; 25 } 26 } 27 //**************************************************************** 28 // Miller_Rabin 算法进行素数测试 29 //速度快,而且可以判断 <2^63的数 30 //**************************************************************** 31 const int S=20;//随机算法判定次数,S越大,判错概率越小 32 LL mult_mod(LL a,LL b,LL mod) //(a*b)%c a,b,c<2^63 33 { 34 a%=mod; 35 b%=mod; 36 LL ans=0; 37 while(b) 38 { 39 if(b&1) 40 { 41 ans=ans+a; 42 if(ans>=mod) 43 ans=ans-mod; 44 } 45 a=a<<1; 46 if(a>=mod) a=a-mod; 47 b=b>>1; 48 } 49 return ans; 50 } 51 LL pow_mod(LL a,LL b,LL mod) // a^b%mod 52 { 53 LL ans=1; 54 a=a%mod; 55 while(b) 56 { 57 if(b&1) 58 { 59 ans=mult_mod(ans,a,mod); 60 } 61 a=mult_mod(a,a,mod); 62 b=b>>1; 63 } 64 return ans; 65 } 66 67 //以a为基,n-1=x*2^t a^(n-1)=1(mod n) 验证n是不是合数 68 //一定是合数返回true,不一定返回false 69 70 bool check(LL a,LL n,LL x,LL t) 71 { 72 LL ret=pow_mod(a,x,n); 73 LL last=ret; 74 for(int i=1;i<=t;i++) 75 { 76 ret=mult_mod(ret,ret,n); 77 if(ret==1 && last!=1 && last!=n-1) return true;//合数 78 last=ret; 79 } 80 if(ret!=1) return true; 81 else return false; 82 } 83 84 // Miller_Rabin()算法素数判定 85 //是素数返回true.(可能是伪素数,但概率极小) 86 //合数返回false; 87 88 bool Miller_Rabin(LL n) 89 { 90 if(n<2)return false; 91 if(n==2) return true; 92 if( (n&1)==0) return false;//偶数 93 LL x=n-1; 94 LL t=0; 95 while( (x&1)==0 ) { x>>=1;t++;} 96 for(int i=0;i<S;i++) 97 { 98 LL a=rand()%(n-1)+1;//rand()需要stdlib.h头文件 99 if(check(a,n,x,t)) 100 return false;//合数 101 } 102 return true; 103 } 104 bool Euler(LL n) 105 { 106 LL i , knum = 0; 107 for(i=1;prime[i]<=n&&i<=len;i++) 108 { 109 if(n%prime[i]==0) 110 { 111 while(n%prime[i]==0) 112 n=n/prime[i]; 113 knum++; 114 } 115 if(knum>=2) break; 116 } 117 if(knum == 1 && n==1) return true; 118 /**此处为n == 1 不是n == 0**/ 119 return false; 120 } 121 void solve(LL n,LL m) 122 { 123 if( (m<=1000000 && s[m] == true) || Miller_Rabin(m) == true) 124 { 125 printf("%I64d ",n-1); 126 return; 127 } 128 LL k = (LL)sqrt(m*1.0); 129 if(k * k == m && Miller_Rabin(k) == true) 130 { 131 printf("%I64d ",n-1); 132 return; 133 } 134 if(Euler(m)==true) 135 { 136 printf("%I64d ",n-1); 137 return; 138 } 139 printf("1 "); 140 } 141 int main() 142 { 143 init(); 144 LL n , m; 145 while(scanf("%I64d",&n)>0) 146 { 147 if(n==-1) break; 148 if(n<=5){ 149 printf("%I64d ",n-1); 150 continue; 151 } 152 m = n; 153 if( (m&1) == 0) 154 { 155 m = m /2; 156 if((m&1)==0) 157 { 158 printf("1 "); 159 continue; 160 } 161 } 162 solve(n,m); 163 } 164 return 0; 165 }