Problem about GCD
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 341 Accepted Submission(s): 52
Last line contains -1, it should be skipped.
[Technical Specification]
m <= 10^18
1 2 3 4 5 -1
0 1 2 3 4
暴力打表,然后找规律,表如下:
1 0
2 1
3 2
4 3
5 4
6 5
7 6
8 1
9 8
10 9
11 10
12 1
13 12
14 13
15 1
16 1
17 16
18 17
19 18
20 1
21 1
22 21
23 22
24 1
25 24
26 25
27 26
28 1
29 28
30 1
31 30
32 1
33 1
34 33
35 1
36 1
37 36
38 37
39 1
40 1
41 40
42 1
43 42
44 1
45 1
46 45
47 46
48 1
49 48
50 49
51 1
52 1
53 52
54 53
55 1
56 1
57 1
58 57
59 58
60 1
61 60
62 61
63 1
64 1
65 1
66 1
67 66
68 1
69 1
70 1
71 70
72 1
73 72
74 73
75 1
76 1
77 1
78 1
79 78
80 1
81 80
82 81
83 82
84 1
85 1
86 85
87 1
88 1
89 88
90 1
91 1
92 1
93 1
94 93
95 1
96 1
97 96
98 97
99 1
100 1
101 100
102 1
103 102
104 1
105 1
106 105
107 106
108 1
109 108
110 1
111 1
112 1
113 112
114 1
115 1
116 1
117 1
118 117
119 1
120 1
121 120
122 121
123 1
124 1
125 124
126 1
127 126
128 1
129 1
130 1
131 130
132 1
133 1
134 133
135 1
136 1
137 136
138 1
139 138
140 1
141 1
142 141
143 1
144 1
我们发现,答案不是n-1就是1.
1的情况:4的倍数(4除外);奇数质因数多于1个的;偶数除以2后质因数多于1个的
n-1的情况: 1,质数;n = p^x(n为奇数,比如27,9,25, 125,3)因 x 可以为1所以质数也在这个集合中, 或 n = 2*p^x(n为偶数,比如142(2*71^1),54(2*3*^3),其中p为质数。
找到规律后,就要尝试。刚开始用Miller_Rabin判素数 + pollard_rho质因数分解结果TLE了,可能是姿势不对。后来换了一种分解法就过了。详见代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
//#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF 1e9
#define MAXN 21
const int maxn = 1000005;
//#define mod 1000000007
#define eps 1e-7
#define pi 3.1415926535897932384626433
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
//ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b);}
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
//****************************************************************
// Miller_Rabin 算法进行素数测试
//速度快,而且可以判断 <2^63的数
//****************************************************************
const int S=20;//随机算法判定次数,S越大,判错概率越小
int prime[maxn];
int c;
bool vis[maxn];
void init()
{
c = 0;
ini(vis);
for(int i = 2;i <= 1000000; i++)
{
if(vis[i]) continue;
prime[c++] = i;
for(int j = i + i;j <= 1000000; j += i) vis[j] = true;
}
}
//计算 (a*b)%c. a,b都是long long的数,直接相乘可能溢出的
// a,b,c <2^63
long long mult_mod(long long a,long long b,long long c)
{
a%=c;
b%=c;
long long ret=0;
while(b)
{
if(b&1){ret+=a;ret%=c;}
a<<=1;
if(a>=c)a%=c;
b>>=1;
}
return ret;
}
long long pow_mod(long long x,long long n,long long mod)//x^n%c
{
if(n==1)return x%mod;
x%=mod;
long long tmp=x;
long long ret=1;
while(n)
{
if(n&1) ret=mult_mod(ret,tmp,mod);
tmp=mult_mod(tmp,tmp,mod);
n>>=1;
}
return ret;
}
//以a为基,n-1=x*2^t a^(n-1)=1(mod n) 验证n是不是合数
//一定是合数返回true,不一定返回false
bool check(long long a,long long n,long long x,long long t)
{
long long ret=pow_mod(a,x,n);
long long last=ret;
for(int i=1;i<=t;i++)
{
ret=mult_mod(ret,ret,n);
if(ret==1&&last!=1&&last!=n-1) return true;//合数
last=ret;
}
if(ret!=1) return true;
return false;
}
// Miller_Rabin()算法素数判定
//是素数返回true.(可能是伪素数,但概率极小)
//合数返回false;
bool Miller_Rabin(long long n)
{
if(n < 2)return false;
if(n == 2)return true;
if((n & 1) == 0) return false;//偶数
long long x = n - 1;
long long t = 0;
while((x & 1) ==0 ){x>>=1;t++;}
for(int i = 0;i < S; i++)
{
long long a=rand()%(n-1)+1;//rand()需要stdlib.h头文件
if(check(a,n,x,t))
return false;//合数
}
return true;
}
bool squre(ll n)
{
ll m = sqrt(n * 1.0);
return m * m == n || (m-1) * (m-1) == n || (m+1) * (m+1) == n;
}
bool solve(ll n)
{
if(Miller_Rabin(n)) return true; //是素数直接返回
int times = 0;
ll m = n;
for(int i = 0;i < c; i++)
{
if(m % prime[i] == 0)
{
times++; //记录不同素因子数,大于2直接返回
if(times >= 2) return false;
while(m % prime[i] == 0)
{
m /= prime[i];
}
}
if(m == 1) return true; //说明能被一个质数完全分解
}
if(m != n) return false; //当m != n时,但m != 1,说明n至少有一个小于1e6和一个大于1e6的质因数,直接返回
if(squre(n)) return true; //若10^6以内的质因数都不能分解,就判断是不是完全平方数,因为10^18最多
//容许两个大于10^6的数相乘
return false;
}
ll n;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
init();
// cout<<prime[c-1]<<endl;
while(~scanf("%I64d",&n))
{
if(n == -1) break;
if(n == 1)
{
puts("0");
continue;
}
if(n != 4 && n % 4 == 0)
{
puts("1");
continue;
}
ll m = n;
if(m % 2 == 0) m /= 2;
if(!solve(m))
puts("1");
else
printf("%I64d\n",n-1);
}
return 0;
}