题目大意
给定集合a,求最大的是大小超过一半的子集的最大公约数的数是什么。
题解
“超过一半”即想到随机化n次后只有\(\frac{1}{2^n}\)的几率错误,于是随机一个数判断它的约数是否是一半以上的数的约数。
一个数的约数个数大约是\(n^{\frac{1}{3}}\)的,直接枚举每个约数时间不可行,不能从“约数能被多少个数整除”于是想到“每个数与当前数的最大公约数处贡献”,从大到小累加一下即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=1000010;
mt19937 rnd(20060309);
int T=10;
int n,ans=1,sum[N],d[N],f[N],cnt;
int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
int deal(int t){
cnt=0;
for(int i=2;i*i<=t;i++){
if(t%i==0){
d[++cnt]=i;
if(i*i!=t)d[++cnt]=t/i;
}
}
d[++cnt]=t;
sort(d+1,d+1+cnt);
for(int i=1;i<=cnt;i++)f[i]=0;
for(int i=1;i<=n;i++){
int g=gcd(sum[i],t);
if(g!=1)f[lower_bound(d+1,d+1+cnt,g)-d]++;
}
for(int i=1;i<=cnt;i++){
for(int j=i+1;j<=cnt;j++)if(d[j]%d[i]==0)f[i]+=f[j];
}
// cout<<"T:"<<t<<"\n";
// for(int i=1;i<=cnt;i++)cout<<d[i]<<":"<<f[i]<<"\n";
int ansn=0;
for(int i=cnt;i>=1&&!ansn;i--)if(f[i]*2>=n)ansn=d[i];
return ansn;
}
signed main(){
n=rd();
for(int i=1;i<=n;i++)sum[i]=rd();
while(T--)ans=max(deal(sum[rnd()%n+1]),ans);
printf("%lld\n",ans);
return 0;
}
标签:约数,return,int,题解,CF364D,ansn,getchar
From: https://www.cnblogs.com/T-water/p/17208893.html