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;
}
posted @ 2022-05-14 00:30  Bellala  阅读(68)  评论(0)    收藏  举报