【题解】CF364D

题目大意

给定集合a,求最大的是大小超过一半的子集的最大公约数的数是什么。

题解

“超过一半”即想到随机化n次后只有12n的几率错误,于是随机一个数判断它的约数是否是一半以上的数的约数。
一个数的约数个数大约是n13的,直接枚举每个约数时间不可行,不能从“约数能被多少个数整除”于是想到“每个数与当前数的最大公约数处贡献”,从大到小累加一下即可。

#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;
}
posted @   flywatre  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示