小Y的绝对战争
2016-06-17 11:42
288 查看
题目描述 Description
小Y与大黄爆发了一场绝对要胜利的战争。(原因是大黄生活作风问题)小Y现在拥有 N 个城池,每个城池都有一个强大值 Wi 。现在没有一条通路连接任意两个城池(通路是双向的)。现在小 Y 想顺次修建若干条通路,使得每修建一条通路都连接了两个原本不连通的城池(联通的定义是两个城池之间存在一条由通路构成的路径)。每修建一条通路 I−J ,那么安全值就会增加 Gcd(Wi,Wj) 。为了确保这场战争的胜利,小 Y 想知道,可能的最大安全值是多少(囧)。
输入描述 Input Description
第一行一个正整数 N ,代表城池的个数。接下来 N 行,每行一个正整数,代表这个城市的强大值。
输出描述 Output Description
一行一个整数,代表最大的安全值。输入样例 Sample Input
41
2
3
输出样例 Sample Output
4 4数据范围及提示 Data Size & Hint
对于 30% 的数据,保证有 n≤1000 。对于 100% 的数据,保证有 n≤1000000 , Wi≤1000000。
分析
注意到对于 Wi≤1000000 ,也就是 gcd≤1000000 ,所以我们从大到小枚举 gcd ,再将其加入到并查集中即可代码
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long LL; const int Size = 1000001; int a[Size]; int b[Size]; int n; int prime[Size]; bool no_prime[Size]; int fa[Size]; int maxn; int find(int); void uni(int,int); int main(){ LL ans = 0; scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); maxn = max(maxn,a[i]); if(b[a[i]]){ ans += a[i]; --n; --i; } else b[a[i]] = fa[i] = i; } for(int i=maxn,k=1;i>=1&&k<=n-1;i-1<=maxn?--i:i=maxn){ int lst = -1; for(int j=1;j*i<=maxn&&k<=n-1;++j) if(b[j*i]){ if(lst!=-1 && find(b[lst*i])!=find(b[j*i])){ ans += i; uni(b[lst*i],b[j*i]); ++k; } lst = j; } } printf("%lld",ans); return 0; } int find(int x){ if(fa[x] != x) fa[x] = find(fa[x]); return fa[x]; } void uni(int x,int y){ fa[find(x)] = find(y); }