这题看上去想拿分层图做啊
f[x][k] 表示 到节点 x 走过的路程为 k + x的最短路 的方案数
然而只有六十分,因为判 0 环太暴力了 //好像应该有 70 ?
于是颓题解的记搜 //分层图的判 0 环似乎不是很可写
就大力搜索大力记忆化啊
判 0 环很神奇,不过跟两遍 spfa 的思路是差不多的,因为最短路树上不会去经过正权环
所以有环一定是 0 环
枚举到点 n 的距离和点 n 的最短路的差,倒着往回搜看会不会搜会当前状态,搜回来了就说明有 0 环
否则统计答案
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cctype> #include<cstdio> #include<queue> using namespace std; typedef long long ll; const int MAXN = 100005, MAXM = 200005; struct EDGE{ int nxt, to, val; EDGE(int NXT = 0, int TO = 0, int VAL = 0) {nxt = NXT; to = TO; val = VAL;} }edge[MAXM << 1]; int t, n, m, k, totedge; int head[MAXN][2], dst[MAXN], vis[MAXN][55]; ll p, f[MAXN][55], ans; bool vs[MAXN], ins[MAXN][55], fns[MAXN][55], GG; priority_queue<pair<int,int> > q1; inline int rd() { register int x = 0; register char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return x; } inline void add(int x, int y, int v, int rev) { edge[++totedge] = EDGE(head[x][rev], y, v); head[x][rev] = totedge; return; } inline void dij() { dst[1] = 0; q1.push(make_pair(0, 1)); while(!q1.empty()) { int x = q1.top().second; q1.pop(); if(vs[x]) continue; vs[x] = true; for(int i = head[x][0]; i; i = edge[i].nxt) { int y = edge[i].to; if(dst[y] > dst[x] + edge[i].val) { dst[y] = dst[x] + edge[i].val; q1.push(make_pair(-dst[y], y)); } } } ans = 0ll; return; } int dfs(int x, int dlt) { if(ins[x][dlt]) { GG = true; return f[x][dlt] = -1; } if(fns[x][dlt]) return f[x][dlt]; ins[x][dlt] = true; for(int i = head[x][1]; i; i = edge[i].nxt) { int y = edge[i].to, dlty = dst[x] + dlt - edge[i].val - dst[y]; if(0 <= dlty && dlty <= k) f[x][dlt] = (f[x][dlt] + dfs(y, dlty)) % p; } fns[x][dlt] = true; ins[x][dlt] = false; return f[x][dlt]; } inline void clearall() { totedge = 0; GG = false; for(int i = 1; i <= n; ++i) { head[i][0] = head[i][1] = 0; vs[i] = false; for(int j = 0; j <= 50; ++j) { f[i][j] = 0ll; fns[i][j] = ins[i][j] = false; vis[i][j] = 0; } } return; } int main() { t = rd(); while(t--) { n = rd(); m = rd(); k = rd(); p = (ll)rd(); register int xx, yy, vv; for(int i = 1; i <= m; ++i) { xx = rd(); yy = rd(); vv = rd(); add(xx, yy, vv, 0); add(yy, xx, vv, 1); } for(int i = 1; i <= n; ++i) dst[i] = 0x3f3f3f3f; dij(); f[1][0] = 1ll; for(int i = 0; i <= k; ++i) ans = (ans + dfs(n, i)) % p; printf("%lld ", GG ? -1 : ans); clearall(); } return 0; }