欢迎 Hack
查看原帖
欢迎 Hack
815504
chenwenmo楼主2024/11/26 09:22

RT。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pli = pair<ll, int>;

const int N = 1e5 + 5, K = 50 + 5;
const ll inf = 1e18;

int n, m;
ll k, mod;
ll dp[N][K]; // dp[i][j] : dis[1][i] == dis1[i] + k 的路径数量
vector<pair<int, ll>> G[N], rG[N]; // 原图,反图
vector<int> G0[N]; // 0边图
int in[N], ord[N], inx; // 入度,topo序
int id[N], pos[N];
ll dis1[N], disu[N], disn[N];
bool vis[N];

void dijkstra(int st, ll *dis, vector<pair<int, ll>> *G) {
    priority_queue<pli, vector<pli>, greater<pli>> pq;
    fill(dis + 1, dis + 1 + n, inf);
    fill(vis + 1, vis + 1 + n, false);
    dis[st] = 0;
    pq.emplace(0, st);
    while (!pq.empty()) {
        int u = pq.top().second;
        pq.pop();
        if (vis[u]) continue;
        vis[u] = true;
        for (auto e : G[u]) {
            int v = e.first;
            ll w = e.second;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                pq.emplace(dis[v], v);
            }
        }
    }
}

void topo() {
    queue<int> q;
    for (int i = 1; i <= n; i++) {
        if (in[i] == 0) q.push(i);
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        ord[u] = ++inx;
        for (int v : G0[u]) {
            if (--in[v] == 0) q.push(v);
        }
    }
}

void init() {
    memset(dp, 0, sizeof(dp));
    memset(in, -1, sizeof(in));
    inx = 0;
}

void clear(int n) {
    for (int i = 1; i <= n; i++) {
        G[i].clear();
        rG[i].clear();
        in[i] = -1;
        G0[i].clear();
    }
}

void Solve() {
    init();

    cin >> n >> m >> k >> mod;
    int u, v; ll w;
    for (int i = 1; i <= m; i++) {
        cin >> u >> v >> w;
        G[u].emplace_back(v, w);
        rG[v].emplace_back(u, w); // 反图
    }

    // 最短路
    dijkstra(1, dis1, G); // 1 到 u
    dijkstra(n, disu, rG); // u 到 n
    dijkstra(n, disn, G); // n 到 u

    // 建0边图
    for (int u = 1; u <= n; u++) {
        for (auto e : G[u]) {
            int v = e.first;
            ll w = e.second;
            if (w == 0) {
                if (in[u] == -1) in[u] = 0;
                if (in[v] == -1) in[v] = 0;
                G0[u].push_back(v);
                in[v]++;
            }
        }
    }

    // 对0边图拓扑排序
    topo();

    // 两种无解的情况
    for (int i = 2; i < n; i++) {
        if (in[i] > 0 && dis1[i] + disu[i] <= dis1[n] + k) {
            cout << -1 << '\n';
            clear(n);
            return;
        }
    }
    if (dis1[n] == 0 && disn[1] == 0) {
        cout << -1 << '\n';
        clear(n);
        return;
    }

    // 排序
    iota(id + 1, id + 1 + n, 1);
    sort(id + 1, id + 1 + n, [&](int i, int j) { return dis1[i] == dis1[j] ? ord[i] < ord[j] : dis1[i] < dis1[j]; });
    for (int i = 1; i <= n; i++) {
        pos[id[i]] = i;
    }
    sort(dis1 + 1, dis1 + 1 + n);

    // 转移
    dp[1][0] = 1 % mod;
    for (int i = 0; i <= k; i++) {
        for (int j = 1; j <= n; j++) {
            int u = id[j];
            for (auto e : G[u]) {
                int v = e.first;
                ll w = e.second;
                if (dis1[pos[u]] + i + w - dis1[pos[v]] <= k && dis1[pos[u]] + i + w - dis1[pos[v]] >= 0) {
                    dp[v][dis1[pos[u]] + i + w - dis1[pos[v]]] += dp[u][i];
                    dp[v][dis1[pos[u]] + i + w - dis1[pos[v]]] %= mod;
                }
            }
        }
    }

    ll ans = 0;
    for (int i = 0; i <= k; i++) ans = (ans + dp[n][i]) % mod;
    cout << ans << '\n';

    clear(n);
}

int main() {
    int T;
    cin >> T;
    while (T--) Solve();
    return 0;
}
2024/11/26 09:22
加载中...