【JZOJ A組】GCD生成樹
阿新 • • 發佈:2018-12-12
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; }