[NOIp2017提高组]逛公园
题目大意:
给你一个有向图,若用dis(u,v)表示从u到v的最短路长度,求从1到n的长度不超过dis(1,n)+k的路径数。
思路:
首先分别预处理出以1,n为起点的单、源最短路。
对于合法的边重构图,然后拓扑排序判环,
BFS时判断一下当前点是否在合法路径上,
如果最后一个点没有被搜到且在合法路径上,那么肯定是一个0环。
最后动态规划,f[i][j]表示长度为dis(1,i)+j的路径数量。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 #include<cstring> 6 #include<algorithm> 7 #include<functional> 8 #include<ext/pb_ds/priority_queue.hpp> 9 inline int getint() { 10 register char ch; 11 while(!isdigit(ch=getchar())); 12 register int x=ch^'0'; 13 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 14 return x; 15 } 16 const int inf=0x7fffffff; 17 const int N=100001,LIM=51; 18 int n,m,lim,mod; 19 struct Edge { 20 int to,w; 21 }; 22 std::vector<Edge> e0[N],e1[N]; 23 inline void add_edge(const int &u,const int &v,const int &w) { 24 e0[u].push_back((Edge){v,w}); 25 e1[v].push_back((Edge){u,w}); 26 } 27 struct Vertex { 28 int id,dis; 29 bool operator > (const Vertex &another) const { 30 return dis>another.dis; 31 } 32 }; 33 int dis0[N],dis1[N]; 34 inline void dijkstra(const int &s,int dis[],const std::vector<Edge> e[]) { 35 static __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q; 36 static __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[N]; 37 for(register int i=1;i<=n;i++) { 38 p[i]=q.push((Vertex){i,dis[i]=i==s?0:inf}); 39 } 40 while(!q.empty()&&q.top().dis!=inf) { 41 const int x=q.top().id; 42 q.pop(); 43 for(register unsigned i=0;i<e[x].size();i++) { 44 const int &y=e[x][i].to,&w=e[x][i].w; 45 if(dis[x]+w<dis[y]) { 46 q.modify(p[y],(Vertex){y,dis[y]=dis[x]+w}); 47 } 48 } 49 } 50 while(!q.empty()) q.pop(); 51 } 52 std::vector<int> top; 53 inline bool check() { 54 static int deg[N]; 55 static std::queue<int> q; 56 memset(deg,0,sizeof deg); 57 for(register int x=1;x<=n;x++) { 58 for(register unsigned i=0;i<e0[x].size();i++) { 59 const int &y=e0[x][i].to,&w=e0[x][i].w; 60 if(dis0[x]+w==dis0[y]) deg[y]++; 61 } 62 } 63 for(register int x=1;x<=n;x++) { 64 if(!deg[x]) q.push(x); 65 } 66 while(!q.empty()) { 67 const int x=q.front(); 68 q.pop(); 69 top.push_back(x); 70 for(register unsigned i=0;i<e0[x].size();i++) { 71 const int &y=e0[x][i].to,&w=e0[x][i].w; 72 if(dis0[x]+w!=dis0[y]) continue; 73 if(!--deg[y]) q.push(y); 74 } 75 } 76 for(register int x=1;x<=n;x++) { 77 if(deg[x]&&dis0[x]+dis1[x]<=dis0[n]+lim) return false; 78 } 79 return true; 80 } 81 inline int calc() { 82 static int f[N][LIM]; 83 memset(f,0,sizeof f); 84 f[1][0]=1; 85 for(register int k=0;k<=lim;k++) { 86 for(register unsigned i=0;i<top.size();i++) { 87 const int &x=top[i]; 88 if(!f[x][k]) continue; 89 for(register unsigned i=0;i<e0[x].size();i++) { 90 const int &y=e0[x][i].to,&w=e0[x][i].w; 91 if(dis0[x]+k+w<=dis0[y]+lim) { 92 (f[y][dis0[x]+k+w-dis0[y]]+=f[x][k])%=mod; 93 } 94 } 95 } 96 } 97 int ans=0; 98 for(register int i=0;i<=lim;i++) { 99 ans=(ans+f[n][i])%mod; 100 } 101 return ans; 102 } 103 inline void reset() { 104 for(register int i=1;i<=n;i++) { 105 e0[i].clear(); 106 e1[i].clear(); 107 } 108 top.clear(); 109 } 110 int main() { 111 for(register int T=getint();T;T--) { 112 n=getint(),m=getint(),lim=getint(),mod=getint(); 113 while(m--) { 114 const int u=getint(),v=getint(),w=getint(); 115 add_edge(u,v,w); 116 } 117 dijkstra(1,dis0,e0); 118 dijkstra(n,dis1,e1); 119 printf("%d\n",check()?calc():-1); 120 reset(); 121 } 122 return 0; 123 }