神tm比赛时多清个零就有60了T T
首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP。设f[i][j]表示比最短路多走i的长度,到j的方案数。
我们发现如果在最短路上的和零边会有后向性,怎么办呢?拓扑排序。
把最短路上的点和零边的点拉出来跑拓扑排序,如果有零环的话必定度数不为0,而且要注意零环必须在<=最短路+k的路径上才输出-1,这个就用刚刚跑出来的1起点到n起点的最短路来判断就好了。
然后先按拓扑序DP出i相同的,然后再DP不在最短路上或者零边的。
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #define MOD(x) ((x)>=mod?(x)-mod:(x)) using namespace std; const int maxn=1000010; struct tjm{int too, dis, pre;}e[2][maxn]; struct poi{int x, dis;}; priority_queue<poi>q; bool operator<(poi a, poi b){return a.dis>b.dis;} int T, x, y, z, n, m, K, mod, top, tot[2], ans; int f[60][maxn], dist[2][maxn], last[2][maxn], d[maxn], st[maxn]; void read(int &k) { int f=1; k=0; char c=getchar(); while(c<‘0‘ || c>‘9‘) c==‘-‘ && (f=-1), c=getchar(); while(c<=‘9‘ && c>=‘0‘) k=k*10+c-‘0‘, c=getchar(); k*=f; } inline void add(int x, int y, int z, int ty){e[ty][++tot[ty]]=(tjm){y, z, last[ty][x]}; last[ty][x]=tot[ty];} inline void dij(int x, int ty) { memset(dist[ty], 32, sizeof(dist[ty])); dist[ty][x]=0; q.push((poi){x, 0}); while(!q.empty()) { poi now=q.top(); q.pop(); if(dist[ty][now.x]!=now.dis) continue; for(int i=last[ty][now.x], too;i;i=e[ty][i].pre) if(dist[ty][too=e[ty][i].too]>dist[ty][now.x]+e[ty][i].dis) { dist[ty][too]=dist[ty][now.x]+e[ty][i].dis; q.push((poi){too, dist[ty][too]}); } } } inline bool topo() { memset(d, 0, sizeof(d)); for(int i=1;i<=n;i++) for(int j=last[0][i], too;j;j=e[0][j].pre) if(dist[0][i]+e[0][j].dis==dist[0][too=e[0][j].too]) d[too]++; top=0; for(int i=1;i<=n;i++) if(!d[i]) st[++top]=i; for(int i=1;i<=top;i++) for(int j=last[0][st[i]], too;j;j=e[0][j].pre) if(dist[0][st[i]]+e[0][j].dis==dist[0][too=e[0][j].too]) { d[too]--; if(!d[too]) st[++top]=too; } for(int i=1;i<=n;i++) if(d[i] && dist[0][i]+dist[i][n]<=dist[0][n]+K) return 0; return 1; } int main() { read(T); while(T--) { memset(last, 0, sizeof(last)); tot[0]=tot[1]=0; read(n); read(m); read(K); read(mod); for(int i=1;i<=m;i++) read(x), read(y), read(z), add(x, y, z, 0), add(y, x, z, 1); dij(1, 0); dij(n, 1); if(!topo()) {puts("-1"); continue;} memset(f, 0, sizeof(f)); f[0][1]=1; ans=0; for(int i=0;i<=K;i++) { for(int j=1;j<=top;j++) for(int k=last[0][st[j]], too;k;k=e[0][k].pre) if(e[0][k].dis+dist[0][st[j]]==dist[0][too=e[0][k].too]) f[i][too]+=f[i][st[j]], f[i][too]=MOD(f[i][too]); for(int j=1;j<=n;j++) for(int k=last[0][j], too, tmp;k;k=e[0][k].pre) if((tmp=i+e[0][k].dis+dist[0][j]-dist[0][too=e[0][k].too])<=K && i!=tmp) f[tmp][too]+=f[i][j], f[tmp][too]=MOD(f[tmp][too]); ans+=f[i][n]; ans=MOD(ans); } printf("%d\n", ans); } }