[省选联考 2020 A 卷] 作业题
P6624 [省选联考 2020 A 卷] 作业题
一道有启发性的矩阵树定理的题。
题目让我们求:
\[\sum_{T}(\sum_{w_i \subseteq T}w_i)*gcd(w_1,...,w_i,...,w_{n - 1})
\]
欧拉反演一下
\[\sum_{d}\phi(d) * \sum_{T, d|w_i}\sum_{w_i \subseteq T}w_i
\]
后面部分可以用矩阵树定理来求,将权值和设成一个多项式\(w_ix + 1\),那么最后权值和就为多项式乘积的一次项系数,那么我们只需在\(\mod x^2\) 的意义下维护多项式。
#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long
#define IN inline
using namespace std;
const int N = 35 * 35, P = 998244353, Lit = 152501;
int n, p[Lit], bz[Lit + 5], pt, st[N], ed[N], ao[Lit], co[N], m;
LL phi[Lit + 5], w[N]; bool vis[Lit + 5];
IN int read() {
int t = 0,res = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) t |= (ch == '-');
for (; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ 48);
return t ? -res : res;
}
void init() {
phi[1] = 1;
for (int i = 2; i <= Lit; i++) {
if (!bz[i]) p[++pt] = i, phi[i] = i - 1;
for (int j = 1; j <= pt && p[j] * i <= Lit; j++) {
bz[p[j] * i] = 1;
if (i % p[j] == 0){phi[p[j] * i] = phi[i] * p[j]; break;}
phi[i * p[j]] = phi[i] * phi[p[j]];
}
}
}
LL fpow(LL x, LL y) {
LL res = 1;
for (; x; x >>= 1, y = y * y % P)
if (x & 1) res = res * y % P;
return res;
}
struct nd{LL f0, f1;}s[N][N];
nd Div(nd x, nd y){
LL a = x.f1, b = x.f0, c = y.f1, d = y.f0;
return nd{b * fpow(P - 2, d) % P, (a * d % P - b * c % P + P) * fpow(P - 2, d * d % P) % P};
}
nd Mul(nd x, nd y) {
LL a = x.f1, b = x.f0, c = y.f1, d = y.f0;
return nd{b * d % P, (a * d + b * c) % P};
}
nd Sub(nd x, nd y) {
return nd{(x.f0 - y.f0 + P) % P, (x.f1 - y.f1 + P) % P};
}
void add(int x, int y, int z1, int z0) {
(s[x][y].f1 += P + z1) %= P, (s[x][y].f0 += P + z0) %= P;
}
LL DET() {
int fl = 0; nd res = nd{1, 0};
for (int i = 1; i < n; i++) {
if (!s[i][i].f0 && !s[i][i].f1) {
for (int j = i + 1; j < n; j++)
if (s[j][i].f0 || s[j][i].f1) {
swap(s[i], s[j]), fl ^= 1; break;
}
}
if (!s[i][i].f0 && !s[i][i].f1) return 0;
nd inv = Div(nd{1, 0}, s[i][i]);
for (int j = i + 1; j < n; j++) {
nd z = Mul(s[j][i], inv);
for (int k = i; k < n; k++) s[j][k] = Sub(s[j][k], Mul(z, s[i][k]));
}
res = Mul(res, s[i][i]);
}
return res.f1;
}
int main() {
n = read(), m = read(), init();
for (int i = 1; i <= m; i++) {
st[i] = read(), ed[i] = read(), w[i] = read();
for (int j = 1; j * j <= w[i]; j++)
if (w[i] % j == 0) {
if (!vis[j]) vis[j] = 1;
if (!vis[w[i] / j]) vis[w[i] / j] = 1;
}
}
int tot = 0;
for (int i = 1; i <= Lit; i++)
if (vis[i]) ao[++tot] = i;
LL ans = 0;
for (int i = 1; i <= tot; i++) {
int cnt = 0;
for (int j = 1; j <= m; j++)
if (w[j] % ao[i] == 0) co[++cnt] = j;
if (cnt < n - 1) continue;
for (int j = 1; j <= cnt; j++) {
add(st[co[j]], ed[co[j]], -w[co[j]], -1), add(ed[co[j]], st[co[j]], -w[co[j]], -1);
add(st[co[j]], st[co[j]], w[co[j]], 1), add(ed[co[j]], ed[co[j]], w[co[j]], 1);
}
(ans += phi[ao[i]] * DET() % P) %= P;
for (int j = 1; j < n; j++)
for (int k = 1; k < n; k++) s[j][k] = nd{0, 0};
}
printf("%lld\n", ans);
}

浙公网安备 33010602011771号