[MdOI R2] Odyssey 拓扑排序上DP

[MdOI R2] Odyssey 拓扑排序上DP

题意

若正整数(a,b)满足

  • 存在正整数(c),使得(a imes b = c^k)

则称为数对((a,b))完美数对

有一个包含(n)个结点,(m)条边的有向无环图,这张图的每条边都有权值和长度两个属性。

如果一条路径(P)满足:

  • (P)从起点开始经过依次为(e_1,e_2,e_3...e_p)(p)条边,对于任意(1 leq i leq p - 1)(e_i)的权值和(e_{i+1})的权值组成完美数对

则称为完美路径

找出图中最长的完美路径,输出长度之和

[nleq10^5\ m leq 2 imes10^5\ k leq10 \wleq10^5 ]

分析

首先处于一个有向无环图,自然希望通过(dp)来解决

先来处理给出的性质:
容易发现这里(c)是任意的,(k)是给定的,从唯一分解定理的角度考虑,我们只需要让每个质因子最终都是(k)的倍数即可。

所以处理方法就是对指数取模(k),要求剩下的指数能够满足,可以发现也是唯一对应的。

然后就考虑(dp)了,我们发现要到达当前边,必须通过前驱点的边的状态

(dp[i][val])表示达到点(i),入边的边权为(val),所能得到的最大长度

[dp[v][val] = max{dp[u][inv(val)] + l} ]

然后在拓扑序上(dp)即可

代码

int n, m, k;
int indeg[maxn];
int ans;

unordered_map<int, int> mp[maxn];

int inv(int w) {
    int res = 1;
    for (int i = 2; i * i <= w; i++) {
        int cnt = 0;
        while (w % i == 0) w /= i, cnt++;
        cnt %= k;
        if (cnt) {
            cnt = k - cnt;
            while (cnt--) {
                res *= i;
                if (res > 100000) return -1;
            }
        }
    }
    if (w > 1) {
        int cnt = k - 1;
        while (cnt--) {
            res *= w;
            if (res > 100000) return -1;
        }
    }
    return res;
}

int yu(int w) {
    int res = 1;
    for (int i = 2; i * i <= w; i++) {
        int cnt = 0;
        while (w % i == 0) w /= i, cnt++;
        cnt %= k;
        while (cnt--)
            res *= i;
    }
    if (w > 1 && k != 1) return res * w;
    else return res;
}


struct Edge {
    int v;
    int win, vin, val;
    Edge(int _v, int _val, int _w) {
        v = _v;
        val = _val;
        win = yu(_w);
        vin = inv(_w);
    }
};

vector<Edge> e[maxn];

void topo() {
    queue<int> q;
    for (int i = 1; i <= n; i++) if (!indeg[i]) q.push(i);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = 0; i < e[u].size(); i++) {
            Edge y = e[u][i];
            mp[y.v][y.vin] = max(mp[y.v][y.vin], mp[u][y.win] + y.val);
            ans = max(ans, mp[y.v][y.vin]);
            indeg[y.v]--;
            if (!indeg[y.v]) q.push(y.v);
        }
    }
    printf("%d", ans);
}

int main() {
    n = readint();
    m = readint();
    k = readint();
    for (int i = 1; i <= m; i++) {
        int a = readint();
        int b = readint();
        int w = readint();
        int v = readint();
        e[a].push_back(Edge(b, v,w));
        indeg[b]++;
    }
    topo();
}
原文地址:https://www.cnblogs.com/hznumqf/p/13855208.html