1. 程式人生 > >數據結構_coprime_sequence(互質序列)

數據結構_coprime_sequence(互質序列)

問題 class 一個數 因數 nor alloc turn 正整數 判斷

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
  最大公因數縮寫是 gcdgcd(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(互質序列)