Loading

[MdOI R2] Odyssey 拓扑排序上DP

[MdOI R2] Odyssey 拓扑排序上DP

题意

若正整数\(a,b\)满足

  • 存在正整数\(c\),使得\(a \times 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}\)的权值组成完美数对

则称为完美路径

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

\[n\leq10^5\\ m \leq 2 \times10^5\\ k \leq10 \\w\leq10^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();
}
posted @ 2020-10-21 22:14  MQFLLY  阅读(94)  评论(0编辑  收藏  举报