本次考试三道题是以前做过的模板题,难度均不大,T1主要是注意数组开long long ,T2则是一道裸的LCA,再次就不赘述,主要说说T3
给定 n 个数,求最大的数 m ,使得 m 是 n 个数中至少一半的数的约数。
注意:m 不一定在 n 个数中,只要满足要求即可。
数据范围:
对 40% 的输入数据 : n≤100
对 100% 的输入数据 :n≤100000;1≤数字的大小≤10^12
我们容易想到枚举每个数的约数,然后再统计每个约数出现的次数,直接check 条件就好,但是这样只能过40%的数据。
正解:
我们考虑每次随机一个数字,那么答案是这个数的约数的概率为1/2,那么我们只需要随机取10—20次,错误的概率就会趋近于0;
现在问题变为如何判断一个数的约数再其他数字中出现的次数,首先暴力肯定是不行的,我们考虑两个数字x,y,我们可以断言满足条件的约数一定是gcd(x,y)的约数,那么我们只要统计和这个数的每种不同的gcd出现了多少次;对于指定的约数k,我们枚举他的倍数1,累加1作为gcd的次数,sum即为k在这些数字里面一共出现了多少次
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<map>
using namespace std;
long long n;
long long a[100001];
long long num[4000001];
long long tot;
map <long long,bool> m; //m表示这个gcd是否出现过
bool check(long long x)
{
long long u=0;
long long i;
for(i=1;i<=n;i++)
{
if(!(a[i]%x)) u++;
}
if(u*2>=n) return true;
return false;
}
long long read()
{
long long k=0,f=1;
char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {k=k*10+(c-'0'); c=getchar();}
return k*f;
}
int main()
{
//freopen("half.in","r",stdin);
//freopen("half.out","w",stdout);
long long i,j,k;
n=read();
for(i=1;i<=n;i++)
a[i]=read();
srand(time(0));
long long s,t;
for(int jj=1;jj<=20;jj++)
{
j=rand()%n+1;
for(i=1;i<=sqrt(a[j]);i++)
{
if(!(a[j]%i))
{
if(!m[i]) {m[i]=1; num[++tot]=i;}
if(!m[a[j]/i]) {m[a[j]/i]=1;num[++tot]=a[j]/i;}
}
}
}
long long ans=1;
for(i=1;i<=tot;i++)
{
if(check(num[i]))
ans=max(ans,num[i]);
}
cout<<ans;
return 0;
}