244. Max Gcd
单点时限: 2.0 sec
内存限制: 512 MB
一个数组a ,现在你需要删除某一项使得它们的gcd 最大,求出这个最大值。
输入格式
第一行输入一个正整数n ,表示数组的大小,接下来一行n 个数,第i 个数为ai 。(2≤n≤105,1≤ai≤109)
输出格式
输出删除掉某个数以后的gcd 的最大值。
样例
Input
4 2 4 8 1
Output
2
Input
4 1 2 3 4
Output
1
提示
样例一:删除第四个元素后,2,4,8的最大公因子为2。
样例二:无论删除哪一个,最大公因子都为1。
思路:
这道题我们有两种解法,前缀和后缀维护,枚举删除每个数的最大gcd,对于删除ai后的gcd = gcd(pre[ i - 1] , sa[ i + 1]),其中,pre代表前缀数组的gcd,sa代表后缀输出的gcd
还有就是贪心解法,我个人认为贪心解法挺巧妙的,
首先我们sort降序排一下所有数,令ans = a[ 0 ] , now = a[0],然后我们for遍历我们刚才排序后的数组,假设我们已经遍历到第 i 个数,其中ans代表之前遍历过的所有数删除其中一个数的最大gcd,now表示之前遍历过的所有数的gcd,而后我们更新ans = max(gcd( ans , a[ i ]) , now) ,这里gcd(ans , a[ i ])代表遍历过的序列删除一个数的最大gcd和当前我们正在便利的这个数的gcd,而now则是相当于删除当前a[ i ]的gcd,我们取其中大的,就能够代表扫过a[ i ]后的删除其中一个数的最大gcd了,于是我们此时再更新一下now = gcd(now , a[ i ]) 就行了,这样一直遍历到最后就能够得到答案了
代码:
#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
return b ? gcd(b,a % b) : a;
}
const int maxn = 1e5 + 10;
int a[maxn];
bool cmp(int x,int y)
{
return x > y;
}
int main()
{
int n;
while (~scanf("%d",&n))
{
for (int i = 0;i < n;i ++)
scanf("%d",&a[i]);
sort(a,a + n,cmp);
int now = a[0],ans = a[0];
for (int i = 1;i < n;i ++)
{
ans = max(gcd(ans,a[i]),now);
//gcd(ans,a[i])表示不删除a[i]与之前删除一个数的gcd
//now之前所有数的gcd,相当于删除a[i]后的与之前数的gcd
//两者取其max就可以表示a[i](包括a[i])之前的删除一个数的最大gcd了
now = gcd(now,a[i]);
}
printf("%d\n",ans);
}
return 0;
}turn 0;
}