Description
Input
Output
Sample Input
5
5 6 7 10 21
Sample Output
17
Data Constraint
Hint
思路
先将权值相等的点消去。
仿照最大生成树算法从大往小枚举边权,假设当前枚举的边权值为 i,这种边显然存在于点权为 ki 的点之间,我们暴力枚举 k,这些点中有些点已经相连(两个点的点权为 k1i 和 k2i且 k1 与 k2 不互质时),而另外的点未相连(两个点的点权为 k1i 和 k2*i 且 k1 与 k2 互质时)。那么我们将所有未相邻的联通块连起来,并计算答案。
枚举倍数的复杂度是调和级数。
复杂度 O(nlogn)。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=1e5+77;
int a[N],fa[N],t[N],n;
int getfa(int x)
{
return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
int main()
{
// freopen("gcd.in","r",stdin);
// freopen("gcd.out","w",stdout);
scanf("%d",&n); int mx=0; ll ans=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]); mx=max(mx,a[i]);
if (!t[a[i]]) fa[i]=t[a[i]]=i; else ans+=a[i];
}
// printf("*\n");
for(int i=mx; i>0; i--)
{
int now=0;
for(int j=1; i*j<=mx; j++)
if(t[i*j])
{
// printf("i=%d j=%d i*j=%d t[i*j]=%d\n",i,j,i*j,t[i*j]);
int x=getfa(t[i*j]);
// printf("*\n");
if(!now) now=x;
else
{
// printf("#\n");
if (now==x) continue;
ans+=i,fa[x]=now;
}
// printf("*\n");
}
}
printf("%lld",ans);
return 0;
}