Description
选出(gelceilfrac{n}{2} ceil)个数字使得他们的最大公约数最大。
Solution
神奇的随机化。
注意到一定会选(gelceilfrac{n}{2}
ceil)个数,那么在原序列中随机选一个数,在答案序列里的概率为(frac{1}{2})。那么我们连续选(10)次,全错的概率就只有(frac{1}{2^{10}}<frac{1}{1000}),已经很小了。(但我要跑(11)次)
对于一个选出来的数(x),我们先把原序列的所有数和(x)取一个(gcd),再依次枚举可能为答案的(gcd),如果它和它的倍数在序列中出现次数(gelceilfrac{n}{2} ceil),那么就可以更新答案。注意到(gcd)可能有很多相同的,要先去重,否则会炸。
Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll t, n, res, a[1000005], b[1000005], c[1000005], s[1000005];
ll read()
{
ll x = 0ll, fl = 1ll; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1ll; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1ll) + (x << 3ll) + ch - '0'; ch = getchar();}
return x * fl;
}
ll gcd(ll x, ll y)
{
return y ? gcd(y, x % y) : x;
}
int main()
{
n = read();
for (ll i = 1; i <= n; i ++ )
a[i] = read();
t = 11ll;
while (t -- )
{
ll pos = 1ll * rand() * rand() % n + 1ll;
ll x = a[pos];
for (ll i = 1; i <= n; i ++ )
b[i] = gcd(a[i], x);
sort(b + 1, b + n + 1);
ll cnt = 0ll, tt = 0ll;
for (ll i = 1; i <= n; i ++ )
{
if (b[i] != b[i + 1])
{
tt ++ ;
c[tt] = b[i];
s[tt] = cnt + 1ll;
cnt = 0ll;
}
else cnt ++ ;
}
ll ans = 0ll;
for (ll i = 1; i <= tt; i ++ )
{
ll sum = 0ll;
for (ll j = 1; j <= tt; j ++ )
if (c[j] % c[i] == 0ll)
sum += s[j];
if (sum >= (n + 1ll) / 2ll) ans = max(ans, c[i]);
}
res = max(res, ans);
}
printf("%lld
", res);
return 0;
}