Lucyna_Kushinada
2024-11-15 18:08:15
很明显这题要我们求的是最小生成树,不过
首先我们先把序列的数去重,因为相同的数可以向另一个和自己相同的数连一条边权为
我们连边肯定是从大的数连向小的数,因为大的数模小的数是显然优于小的数模大的数的,于是我们把数组从小到大排序。
对于一个
连完之后跑最小生成树即可。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define N 101145
//#define int long long
int n,a[N];
const int lim=1e7;
set<int>s;
struct edge{
int u,v,w;
edge(int a,int b,int c){u=a,v=b,w=c;}
};
vector<edge>e;
inline bool cmp(edge x,edge y){
return x.w<y.w;
}
struct DSU{
int fa[N];
inline void init(){
rep(i,1,n){
fa[i]=i;
}
}
inline int ask(int k){
if(k==fa[k]){
return fa[k];
}
return fa[k]=ask(fa[k]);
}
inline void mg(int x,int y){
//y<-x
int fx=ask(x),fy=ask(y);
if(fx==fy)return;
fa[fx]=fy;
}
}b;
inline long long kruskal(){
int cnt=0;
long long ans=0;
b.init();
for(edge x:e){
int u=x.u,v=x.v,w=x.w;
if(b.ask(u)==b.ask(v)){
continue;
}
ans+=w;
cnt++;
b.mg(u,v);
if(cnt==n-1){
break;
}
}
return ans;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
rep(i,1,n){
cin>>a[i];
s.insert(a[i]);
}
int cnt=0;
for(int x:s){
a[++cnt]=x;
}
n=cnt;
/*
a>b
max(a%b)=b-1
b%a=b
*/
sort(a+1,a+1+n);
rep(i,1,n){
int l=a[i];
while(l<=lim){
int r=min(l+a[i],lim);
int id=lower_bound(a+i+1,a+n+1,l)-a;
if(a[id]<r&&id!=n+1){
e.push_back(edge(i,id,a[id]%a[i]));
}
l+=a[i];
}
}
sort(e.begin(),e.end(),cmp);
cout<<kruskal();
return 0;
}