把一条边 \(w\) 写成 \(wx+1\),则生成树边权积的一次项就是答案。
求逆: \((ax+b)^{-1}\equiv(-\frac{a}{b^2}x+\frac{1}{b}) \pmod {x^2}\)
Code
using ll = long long;
const int N = 31;
const int MOD = 998244353;
struct Poly {
ll a, b;
Poly(ll a = 0, ll b = 0) : a(a), b(b) {}
} a[N][N];
ll Pow(ll a, int p = MOD - 2) {
ll ans = 1;
for(; p; p >>=1, a = a * a % MOD)
if(p & 1) ans = ans * a % MOD;
return ans;
}
Poly operator+ (Poly x, Poly y) {
return Poly((x.a + y.a) % MOD, (x.b + y.b) % MOD);
}
Poly operator- (Poly x, Poly y) {
return Poly((x.a + MOD - y.a) % MOD, (x.b + MOD - y.b) % MOD);
}
Poly operator* (Poly x, Poly y) {
return Poly((x.a * y.b + x.b * y.a) % MOD, x.b * y.b % MOD);
}
Poly Inv(Poly x) {
ll tmp = Pow(x.b);
return Poly(MOD - x.a * tmp % MOD * tmp % MOD, tmp);
}
ll Det() {
Poly ans = Poly(0, 1);
for(int i = 1; i < n; ++i) {
int pos = 0;
for(int j = i; j <= n; ++j) if(a[j][i].b) {
pos = j; break;
}
if(!pos) return 0;
if(i != pos) ans = ans * -1, swap(a[i], a[pos]);
for(int j = i + 1; j < n; ++j) {
Poly tmp = a[j][i] * Inv(a[i][i]);
for(int k = 1; k < n; ++k) a[j][k] = a[j][k] - a[i][k] * tmp;
}
}
for(int i = 1; i < n; ++i) ans = ans * a[i][i];
return ans.a;
}
void Add(int u, int v, int w) {
Poly t(w, 1);
a[u][u] = a[u][u] + t;
a[v][v] = a[v][v] + t;
a[u][v] = a[u][v] - t;
a[v][u] = a[v][u] - t;
}