【题意】他要让一些人有联络方式, 使得每个人都可以直接戒者间接的联系其他人。当然, 为了让地下组织保持隐蔽, 建立的联络方式越少越好。 Nc现在有m对可以选择建立的联络方式。 对于每对选择, 都有一个特定的花费。 建立好一个完善的联络方式的总花费, 是选择的每对关系的花费的最大公约数。 当然,建立好一个完善联络方式的方法也还是不唯一。 现在nc想知道, 对于所有的可能的方法, 都会有一个总花费。 他想知道这些总花费的最小公倍数。
【思路】记录图中边权的所有质因数,枚举这些质因数x最为最大公约数的因数,将x的次数转化成克鲁斯卡尔的费用,用克鲁斯卡尔跑一边,x次数最小的就是这条路的最大公因数,乘入ans。
【代码】
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=1003;
const int maxm=100005;
const ll mod=(ll)1<<31;
struct data{
int u,v,w;
bool operator<(const data&b)const{
return w>b.w;
}
}e[maxm*2],g[maxm*2];
int n,m,pt=0,p[maxm],num,fa[maxm],vst[maxm];
ll ans=1;
inline int get(){
char c;while(!isdigit(c=getchar()));
int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
return v;
}
inline void getprime(){
memset(vst,0,sizeof(vst));
for(int t=1;t<=m;++t){
int c=g[t].w;
for(int i=2;i*i<=g[t].w;++i)if(c%i==0){
while(c%i==0)c/=i;
if(!vst[i])p[++pt]=i;
++vst[i];
}
if(c>1&&!vst[c])p[++pt]=c;++vst[c];
}
}
inline void gettot(int x,int pri){//将质因数的次数作为krus的边权
int t=0;int c=g[x].w;e[++num]=g[x];
while(c%pri==0)c/=pri,++t;
e[num].w=t;
}
inline int Find(int x){
if(fa[x]==x)return fa[x];
else return (fa[x]=Find(fa[x]));
}
inline int krus(){
int cnt=0,tme=0;
sort(e+1,e+1+num);
for(int i=1;i<=n;++i)fa[i]=i;
for(int i=1;i<=num;++i){
int x=Find(fa[e[i].u]);
int y=Find(fa[e[i].v]);
if(x!=y)++cnt,fa[y]=x,tme=e[i].w;
}
if(cnt==n-1)return tme;
else return 0;
}
inline ll Pow(int a,int b){
ll tmp=a,ret=1;
while(b){
if(b&1)ret=ret*tmp%mod;
tmp=tmp*tmp%mod;
b>>=1;
}
return ret;
}
int main(){
n=get();m=get();
for(int i=1;i<=m;++i)g[i].u=get(),g[i].v=get(),g[i].w=get();
getprime();
int tmp=0;
for(int i=1;i<=pt;++i)if(vst[p[i]]>=n-1){//枚举质因数
num=0;
for(int j=1;j<=m;++j)if(g[j].w%p[i]==0)gettot(j,p[i]);
if(num>=n-1){
int t=krus();
if(t)ans=ans*Pow(p[i],t)%mod;
}
}
printf("%lld\n",ans);
return 0;
}