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。
输入示例 | 输出示例 |
31 1 1 | 1 |
输入示例 | 输出示例 |
52 2 2 3 2 | 2 |
输入示例 | 输出示例 |
41 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 #include2 #include 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 =0; i--) //for(i=n-1;i>0;i--)40 {41 if(i==n-1)42 gcd = p[n-1];43 else44 gcd = Getgcd(p[i],right[i+1]);45 right[i] = gcd;46 }47 48 int maxgcd = -1;49 for(i=0; i maxgcd) maxgcd = gcd;58 }59 printf("%d\n",maxgcd);60 61 // free(p);62 return 0;63 }