hdu 4910 Problem about GCD

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


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
 

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
 

暴力打表,然後找規律,表如下:

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;
}



發佈了52 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章