數據結構_coprime_sequence(互質序列)
coprime_sequence(互質序列)
問題描述
顧名思義,互質序列是滿足序列元素的 gcd 為 1 的序列。比如[1,2,3],
[4,7,8],都是互質序列。 [3,6,9]不是互質序列。現在並不要求你找出一個互質
序列,那樣太簡單了!真正的問題描述是:給定一個序列,刪除其中一個元素使
得剩下元素的 gcd 最大,輸出這個 gcd。
★數據輸入
輸入第一行為一個正整數 n。 第二行為 n 個正整數 ai(1<=ai<=10^9)。
80%的數據 2<=n<=1000.
100%的數據 2<=n<=100000.
★數據輸出
輸出一個正整數,表示最大的 gcd。
輸入示例 |
輸出示例 |
3 1 1 1 |
1 |
輸入示例 | 輸出示例 |
5 2 2 2 3 2 |
2 |
輸入示例 | 輸出示例 |
4 1 2 4 8 |
2 |
★Hint
最大公因數縮寫是 gcd。 gcd(a,b,c)=gcd(a,gcd(b,c)).
解題思路
暴力算法小規模可以,但是復雜度達到O(n^2),大規模數據超時。因此必須采用更好的算法。
期初,我的想法是將從左到右算過的數據存下來,即開一個數組,將第1個數的gcd(本身)存在第1個位置,將第1~2個數的gcd存在第2個位置,1~3個數的gcd存在第3個位置,以此類推。
而其中第1~n個數的gcd可由gcd( 1~(n-1)的gcd , 第n個數 )求得 是遞推的過程,復雜度O(n)。
但僅僅這樣只比暴力節省一半時間。因此,仿照前面的過程,引入從右到左的gcd計算
開等長數組left[] right[] ,將 從左到右 和 從右到左 的gcd遞推計算結果分別存入left[] 與right[]
那麽除掉下標為 i 的數,其他數的為gcd( left[i-1] , right[i+1]) 首尾做特殊判斷
這樣遍歷一遍,就能找到gcd_max
code
1 #include <stdio.h> 2#include <stdlib.h> 3 4 int p[100002] = {0}; 5 int left[100002] = {0}; 6 int right[100002] = {0}; 7 8 void swap(int &a, int &b) 9 { 10 a ^= b; 11 b ^= a; 12 a ^= b; 13 } 14 15 int Getgcd(int n, int m) 16 { 17 if (n < m) swap(n, m); 18 return n%m == 0 ? m : Getgcd(m, n%m); 19 } 20 21 int main() 22 { 23 // freopen("test.txt","r",stdin); 24 int n, i, j; 25 scanf("%d", &n); 26 // int *p = (int *)malloc(sizeof(int)*n); 27 for (i = 0; i < n; i++) 28 scanf("%d", p + i); 29 30 int gcd = -1; 31 for(i=0; i<n; i++) //for(i=0;i<n-1;i++) 32 { 33 if(i==0) 34 gcd = p[0]; 35 else 36 gcd = Getgcd(p[i],left[i-1]); 37 left[i] = gcd; 38 } 39 for(i=n-1; i>=0; i--) //for(i=n-1;i>0;i--) 40 { 41 if(i==n-1) 42 gcd = p[n-1]; 43 else 44 gcd = Getgcd(p[i],right[i+1]); 45 right[i] = gcd; 46 } 47 48 int maxgcd = -1; 49 for(i=0; i<n; i++) // except p[i] 50 { 51 if(i==0) 52 gcd = right[1]; 53 else if(i==n-1) 54 gcd = left[n-2]; 55 else 56 gcd = Getgcd(left[i-1],right[i+1]); 57 if(gcd>maxgcd) maxgcd = gcd; 58 } 59 printf("%d\n",maxgcd); 60 61 // free(p); 62 return 0; 63 }
數據結構_coprime_sequence(互質序列)