您的位置:首页 > 其它

小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

4

1

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);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数学