给你
n
n
n个数,求一个尽量大的数,使得数列中有超过
n
2
\frac{n}{2}
2n个数能被该数整除。
数
a
i
≤
1
0
12
a_i \leq 10^{12}
ai≤1012
发现每一个数出现在能被整除的集合中的概率均
≥
1
2
≥\frac{1}{2}
≥21,于是考虑随机。每一次猜测一个数在这个集合中,然后计算与其它数的gcd。最后查找一个最大的出现次数超过
n
2
\frac{n}{2}
2n的gcd即可。(若
r
e
s
[
i
]
∣
r
e
s
[
j
]
res[i]|res[j]
res[i]∣res[j]则
s
u
m
[
i
]
+
=
s
u
m
[
j
]
sum[i]+=sum[j]
sum[i]+=sum[j])
我们分析一下这样做的正确率。每一次选对的概率
≥
1
2
≥\frac{1}{2}
≥21,所以说一次选错的概率
≤
1
2
\leq \frac{1}{2}
≤21,即随机
x
x
x次的成功率为
1
−
1
2
x
\Large 1-\frac{1}{2^x}
1−2x1。当
x
x
x取约
14
14
14时,其成功率可以接受。
#include<bits/stdc++.h>
#define reg register
#define ll long long
using namespace std;
const int mn = 1000005;
ll a[mn], res[mn];
int sum[mn];
inline ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
int main()
{
srand(time(NULL));
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%I64d", &a[i]);
ll ans = 1;
for(int T = 0; T < 13; T++)
{
int pos = ((rand() << 15) + rand()) % n + 1;
if(a[pos] <= ans) continue;
ll maxs = 1;
for(reg int i = 1; i <= n; i++)
res[i] = gcd(a[i], a[pos]), maxs = max(res[i], maxs);
if(maxs <= ans) continue;
sort(res + 1, res + 1 + n); int cnt = 0;
for(reg int i = 1; i <= n; i++)
{
if(res[i] != res[i - 1])
res[++cnt] = res[i], sum[cnt] = 0;
++sum[cnt];
}
for(reg int i = cnt; i; i--)
{
if(ans >= res[i]) break;
int tmp = 0;
for(int j = i; j <= cnt; j++)
if(res[j] % res[i] == 0) tmp += sum[j];
if((tmp << 1) >= n) {ans = res[i]; break;}
}
}
printf("%I64d\n", ans);
}