HDU 6954 Minimum spanning tree

题意

给一个$n(\le 10^7)$,求由$n-1$个点$2$, $3$, $\cdots$, $n$构成的最小生成树的边权和,其中点$a$, $b$之间的连边的权值为$\text{lcm} (a,b)$。

思路

考虑加点连边,若加入$u$连接到$v$,则权值和增加$\text{lcm}(a,b)\ge u$,下界当且仅当$v|u$时取得。则当所有数都与小于其自身的某个因数(若存在。不妨设为最小质因子)连接时,权值和增量最小,为加入的数本身。此时除$2$到$n$之间所有质数外,其他数均与其最小质因子连接,则问题转化为将$2$到$n$之间所有质数为树根的子树连接成一棵树。考虑边权为$\text{lcm}$,则将树根间相连最优。又当$p,q\in prime$时,$\text{lcm}(p,q)=pq$,则将$3$到$n$的所有质数与$2$相连最优。

由此可得答案为$\displaystyle \sum_{i=3}^{n}i+\sum_{i=3}^{n}[i\in prime]i$。

时间复杂度$\mathcal{O}(n)$。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<bits/stdc++.h>
using namespace std;
#define debug printf("%d %s\n",__LINE__,__FUNCTION__);fflush(stdout)
using ll=long long;using i64=long long;using db=double;
using u32=unsigned int;using u64=unsigned long long;using db=double;
using pii=pair<int,int>;using vi=vector<int>;
using qi=queue<int>;using pqi=priority_queue<int>;using si=set<int>;
#define pb push_back
#define mk make_pair
#define ins insert
#define era erase
#define fi first
#define se second
#define lowbit(x) x&-x
#define ALL(a) a.begin(),a.end()
const int INF=0x3f3f3f3f;
const ll INFLL=0x3f3f3f3f3f3f3f3f;
const double PI=acos(-1.0);
template<class T>inline bool chkmin(T&a,T b){return b<a?a=b,true:false;}
template<class T>inline bool chkmax(T&a,T b){return a<b?a=b,true:false;}
int _w,_t;FILE* _f;
#define MULTI_CASES

const int N=1e7+7;
int n,notpr[N];
ll sum[N];

void init(){
notpr[0]=notpr[1]=1;
sum[1]=-4;
for(int i=2;i<N;i++){
sum[i]=sum[i-1]+i;
if(!notpr[i]){
sum[i]+=i;
for(int j=i<<1;j<N;j+=i){
notpr[j]=1;
}
}
}
}

void solve(){
scanf("%d",&n);
printf("%lld\n",sum[n]);
}

int main(){
init();
#ifdef MULTI_CASES
_w=scanf("%d",&_t);while(_t--)
#endif
solve();
return 0;
}