传送门
为什么世界上会有这么傻的题啊……我佛了
很显然就是矩阵树强行缝合莫反
设f(n)f(n)f(n)表示所有边权gcd\gcdgcd为nnn的生成树权值和,g(d)g(d)g(d)表示所有边权都是 ddd的倍数的生成树权值和
g(d)=∑d∣nf(n)g(d)=\sum_{d\mid n}f(n)g(d)=d∣n∑f(n)
f(d)=∑d∣ng(n)μ(nd)f(d)=\sum_{d\mid n}g(n)\mu(\frac nd)f(d)=d∣n∑g(n)μ(dn)
做完了
开权值大小个vector,把每条边压到边权的约数的vector中
如果一个vector中边数小于n−1n-1n−1就跳过,否则对每条边构造(wx+1)(wx+1)(wx+1)算矩阵树得到ggg,然后无脑算出fff统计答案就好了
显然矩阵树次数不会超过O(md(V)n)=O(nd(V))O(\frac {md(V)}n)=O(nd(V))O(nmd(V))=O(nd(V)),总复杂度O(n4d(v))O(n^4d(v))O(n4d(v))
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
using namespace std;
struct edge{int u,v,w;};
typedef long long ll;
const int MOD=998244353,N=152501;
inline int qpow(int a,int p)
{int ans=1;while (p){if (p&1) ans=(ll)ans*a%MOD;a=(ll)a*a%MOD;p>>=1;}return ans;
}
#define inv(x) qpow(x,MOD-2)
int np[N+5],pl[N+5],mu[N+5],cnt;
inline void init()
{np[1]=mu[1]=1;for (int i=2;i<=N;i++){if (!np[i]) mu[pl[++cnt]=i]=-1;for (int j=1,x;(x=i*pl[j])<=N;j++){np[x]=1;if (i%pl[j]==0) break;mu[x]=(MOD-mu[i])%MOD;}}
}
inline int add(const int& x,const int& y){return x+y>=MOD? x+y-MOD:x+y;}
inline int dec(const int& x,const int& y){return x<y? x-y+MOD:x-y;}
struct poly{int x,y;poly(const int& x=0,const int& y=0):x(x),y(y){}};
inline poly operator +(const poly& a,const poly& b){return poly(add(a.x,b.x),add(a.y,b.y));}
inline poly operator -(const poly& a,const poly& b){return poly(dec(a.x,b.x),dec(a.y,b.y));}
inline poly operator *(const poly& a,const poly& b){return poly(((ll)a.x*b.y+(ll)a.y*b.x)%MOD,(ll)a.y*b.y%MOD);}
inline poly operator /(const poly& a,const poly& b){ll t=inv(b.y);return poly(dec((ll)a.x*b.y%MOD,(ll)a.y*b.x%MOD)*t%MOD*t%MOD,a.y*t%MOD);}
int n,mx;
poly g[35][35];
inline int det()
{poly ans(0,1);for (int i=1;i<n;i++){ans=ans*g[i][i];for (int j=i+1;j<n;j++){poly t=g[j][i]/g[i][i];for (int k=i;k<n;k++)g[j][k]=g[j][k]-g[i][k]*t;} }return ans.x;
}
vector<edge> lis[N+5];
int F[N+5],G[N+5];
int main()
{init();int m;scanf("%d%d",&n,&m);for (int i=1;i<=m;i++){edge e;scanf("%d%d%d",&e.u,&e.v,&e.w);mx=max(mx,e.w);for (int i=1;i*i<=e.w;i++)if (e.w%i==0){lis[i].push_back(e);if (i*i<e.w) lis[e.w/i].push_back(e);}}for (int k=1;k<=mx;k++){if ((int)lis[k].size()<n-1) continue;for (int i=1;i<=n;i++)for (int j=1;j<=n;j++)g[i][j]=poly(0,0);for (vector<edge>::iterator it=lis[k].begin();it!=lis[k].end();++it){poly t(it->w,1);int u=it->u,v=it->v;g[u][u]=g[u][u]+t,g[v][v]=g[v][v]+t;g[u][v]=g[u][v]-t,g[v][u]=g[v][u]-t; } G[k]=det();}for (int d=1;d<=mx;d++)for (int i=1;i*d<=mx;i++)F[d]=(F[d]+(ll)G[i*d]*mu[i])%MOD;int ans=0;for (int i=1;i<=mx;i++) ans=(ans+(ll)i*F[i])%MOD;printf("%d\n",ans);return 0;
}