策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从N号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到N号点的最短路长为d,那么策策只会喜欢长度不超过d+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对P取模。
如果有无穷多条合法的路线,请输出−1
Solution
看这像个分层图(其实也是分层图2333),首先一眼看到最短路计数,30pts到手。。
我们先把最短路DAG搞出来,拓扑一遍。
什么情况有无穷多解,有0环,我们拓扑完之后,如果还有点有入度,就是无解。
考虑到转移是和k相关的,而且是从小往大转移的,所以我们在枚举k之后,对于i->i转移的转移,我们按照拓扑序进行dp,对于i->i+k的转移,按照分层图的顺序转移就可以了。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define N 100002 #define M 200002 #define mm make_pair using namespace std; queue<int>q1; priority_queue<pair<int,int> >q; int dis[N],du[N],head[N],tot,n,t[N],tt,T,m,k,p,dp[N][52],ans,tttt; bool vis[N]; struct fdd{ int n,to,l; }e[M]; inline void unit(){ tot=0; memset(head,0,sizeof(head)); memset(dp,0,sizeof(dp));tt=0;tttt=0; memset(du,0,sizeof(du)); } inline void add(int u,int v,int l){ e[++tot].n=head[u]; e[tot].to=v;e[tot].l=l; head[u]=tot; } inline void dij(int s){ memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[s]=0;q.push(mm(0,s)); while(!q.empty()){ int u=q.top().second;q.pop(); if(vis[u])continue;vis[u]=1; for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(dis[v]>dis[u]+e[i].l){ dis[v]=dis[u]+e[i].l; q.push(mm(-dis[v],v)); } } } } inline void topo(){ for(int i=1;i<=n;++i)if(!du[i])q1.push(i); while(!q1.empty()){ int u=q1.front();q1.pop();t[++tt]=u; for(int i=head[u];i;i=e[i].n)if(dis[e[i].to]==dis[u]+e[i].l){ int v=e[i].to; if(!--du[v])q1.push(v); } } for(int i=1;i<=n;++i)if(du[i])tttt=1; } inline int rd(){ int x=0;char c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c)){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return x; } int main(){ T=rd(); while(T--){ unit(); int u,v,w; n=rd();m=rd();k=rd();p=rd(); for(int i=1;i<=m;++i){ u=rd();v=rd();w=rd();add(u,v,w); } dij(1); memset(vis,0,sizeof(vis)); for(int u=1;u<=n;++u){ for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(dis[u]+e[i].l==dis[v])du[v]++; } } topo(); if(tttt){ printf("-1\n"); continue; } dp[1][0]=1; for(int i=0;i<=k;++i){ for(u=1;u<=tt;++u) for(int j=head[t[u]];j;j=e[j].n)if(dis[t[u]]+e[j].l==dis[e[j].to]){ int v=e[j].to; (dp[v][i]+=dp[t[u]][i])%=p; } for(int u=1;u<=n;++u) for(int j=head[u];j;j=e[j].n)if(dis[u]+e[j].l!=dis[e[j].to]){ int v=e[j].to; int kk=dis[u]-dis[v]+e[j].l+i; if(kk<=k)(dp[v][kk]+=dp[u][i])%=p; } } ans=0; for(int i=0;i<=k;++i)(ans+=dp[n][i])%=p; printf("%d\n",ans); } return 0; }