NOIP2017 Day1T3
最短路+topsort+dp
求出1到所有点的单源最短路。
所有edge(x,y)满足dis[x]+w[e]≥dis[y],
则大于最短路的值不会减少。
设状态f[i][j]为到达i点时经过的长度为dis[i]+j(j≤k)的路径数.
因此对于一个节点可以扩展出其他k个新结点.
分别表示不同的距离(dis[x]~dis[x]+k).
这就是一个分层图,同层的点之间进行转移,或者向上层的点进行转移,不会向下层的点进行转移。
那么是在分层图上求路径总数。
自然 f[1][0]=1,
做topsort时进行dp转移。
topsort后
一个点没有deg,它的f之和值即为路径总数.
否则,它的路径总数为无穷.
统计sigma(f[n][0...k])。
总时间复杂度 O(T(mlogn+mk))
#include<stdio.h> #include<algorithm> #include<ctype.h> #include<string.h> #include<queue> #define FOR(i,s,t) for(register int i=s;i<=t;++i) #define VIS(now) for(register int e=las[now];e;e=nxt[e]) #define pos(x,y) (x+(y)*n) #define pa pair<int,int> #define mp(x,y) make_pair(x,y) using std::priority_queue; using std::pair; using std::make_pair; const int N=800011,M=1600011,inf=(1<<30); priority_queue<pa>heap; inline char nc(){ static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ int ret=0;char ch=nc(); while(!isdigit(ch))ch=nc(); while(isdigit(ch))ret=((ret+(ret<<2))<<1)+(ch^'0'),ch=nc(); return ret; } int nxt[M],las[N],to[M],w[M],dis[N],vis[N],l[N*51],r[N*51],t[M*51],deg[N*51],f[N*51],que[N*51]; int tot,cnt,n,m,k,p,T,now,ans,head,tail; inline void add(int x,int y,int z){ nxt[++tot]=las[x];las[x]=tot;to[tot]=y;w[tot]=z; } inline void DJ(){ int now; dis[1]=0; heap.push(mp(0,1)); while(!heap.empty()){ now=heap.top().second; heap.pop(); if(vis[now])continue; vis[now]=1; VIS(now) if(dis[now]+w[e]<dis[to[e]]){ dis[to[e]]=dis[now]+w[e]; heap.push(mp(-dis[to[e]],to[e])); } } } int x,y,z; int main(){ T=read(); die:; while(T--){ ans=tot=cnt=0; n=read();m=read();k=read();p=read(); FOR(i,1,n)las[i]=0,dis[i]=inf,vis[i]=0; FOR(i,1,pos(n,k))f[i]=0,deg[i]=0; f[1]=1; while(m--)x=read(),y=read(),z=read(),add(x,y,z); DJ(); FOR(i,1,n) FOR(j,0,k){ l[pos(i,j)]=cnt+1; VIS(i) if(j+dis[i]+w[e]-dis[to[e]]<=k) ++deg[t[++cnt]=pos(to[e],j+dis[i]+w[e]-dis[to[e]])]; r[pos(i,j)]=cnt; } head=1,tail=0; FOR(i,1,pos(n,k)) if(!deg[i]) que[++tail]=i; while(head<=tail){ now=que[head++]; FOR(i,l[now],r[now]){ --deg[t[i]]; f[t[i]]+=f[now]; if(f[t[i]]>=p)f[t[i]]-=p; if(!deg[t[i]])que[++tail]=t[i]; } } FOR(i,0,k){ if(deg[pos(n,i)]){ puts("-1"); goto die; } ans+=f[pos(n,i)]; if(ans>=p)ans-=p; } printf("%d\n",ans); } return 0; }