cf1654 D. Potion Brewing Class
题意:
构造一个长为 n 的正整数组,要求满足 n-1 个比例关系 \(a_i/a_j=x_k/y_k, (i\neq j,k=1,\cdots ,n-1)\)
问数组的和最小能是多少,要取模。保证给定的关系能确定所有 \(a_i\)
\(n\le 2e5, 1\le x, y\le n\) ,都是整数
思路:
实际上这些关系就是一棵树。
一个简单的思路是置根节点的值为1,沿着树dfs确定每个节点的值。这样就会得到一堆分数。假设所有分数的分母的最小公倍数为 lcm ,把每个数乘上 lcm 再求和就是答案。
但是中间要取模,取模后就没法求 lcm 了。我们改为维护 lcm 的质因子分解形式,记录每个质因子的最大指数。
最后统计答案不要写复杂了,可以随便取模,直接一路乘 \(x^{-1}y\) 即可
若没看懂请移步此 https://zhuanlan.zhihu.com/p/484358369
map<int,int> fac[N];
void init() { //预处理每个数的质因子分解
for(int i = 2; i < N; i++) {
int x = i;
for(int d = 2; d <= i / d; d++)
while(x % d == 0) x /= d, fac[i][d]++;
if(x > 1) fac[i][x]++;
}
}
void dfs1(int u, int fa) { //计算所有分母的lcm(这等于根节点的权值)
for(auto &[v,x,y]: G[u]) if(v != fa) {
for(auto &[p,c]: fac[y]) cnt[p] -= c; //细节:先减再加
for(auto &[p,c]: fac[x]) cnt[p] += c, maxc[p] = max(maxc[p], cnt[p]);
dfs1(v, u);
for(auto &[p,c]: fac[y]) cnt[p] += c; //回溯
for(auto &[p,c]: fac[x]) cnt[p] -= c;
}
}
void dfs2(int u, int fa, ll val) { //统计答案
(ans += val) %= mod;
for(auto &[v,x,y]: G[u]) if(v != fa)
dfs2(v, u, val * inv(x) % mod * y % mod);
}
void sol() {
cin >> n;
for(int i = 1; i <= n; i++) G[i].clear(); //清空
fill(maxc, maxc+1+n, 0), fill(cnt, cnt+1+n, 0), val = 1, ans = 0;
for(int i = 1; i < n; i++) { //读入树
int u, v, x, y; cin >> u >> v >> x >> y;
G[u].pb({v,x,y}), G[v].pb({u,y,x});
}
dfs1(1, 0);
for(int i = 2; i <= n; i++)
(val *= qmi(i, maxc[i])) %= mod;
dfs2(1, 0, val);
cout << ans << endl;
}

浙公网安备 33010602011771号