【题解】
直接把松弛操作中dis[to]=dis[now]+e[i].dis改成dis[to]=dis[now]*e[i].dis是不行的,因为这样做会爆long long. 同时也可以发现在最短路中我们并不能边松弛边取模,这会导致答案错误。
其实我们可以把边权取个log. 因为log(M*N)=logN+logM, 所以转化成了加法的操作,这就变成了传统的最短路。我们在最短路中顺便记录路径,然后再顺着路径走一遍求出边权之积即可。
1 // luogu-judger-enable-o2 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #define N 1010 6 #define M 1000010 7 #define rg register 8 #define inf (1e9) 9 #define LL long long 10 #define Mod (9987) 11 using namespace std; 12 int n,m,s,tot,last[N],pos[N],from[N],way[N]; 13 LL ans=0; 14 double dis[N]; 15 struct edge{ 16 int to,pre,dis; 17 }e[M]; 18 struct heap{ 19 int poi; 20 double dis; 21 }h[N]; 22 inline int read(){ 23 int k=0,f=1; char c=getchar(); 24 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 25 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 26 return k*f; 27 } 28 inline void add(int x,int y,int z){ 29 e[++tot]=(edge){y,last[x],z}; last[x]=tot; 30 } 31 inline void up(int x){ 32 int fa; 33 while((fa=x>>1)&&h[fa].dis>h[x].dis){ 34 swap(h[x],h[fa]); swap(pos[h[x].poi],pos[h[fa].poi]); 35 x=fa; 36 } 37 } 38 inline void down(int x){ 39 int son; 40 while((son=x<<1)<=tot){ 41 if(son<tot&&h[son].dis>h[son+1].dis) son++; 42 if(h[son].dis<h[x].dis){ 43 swap(h[x],h[son]); swap(pos[h[x].poi],pos[h[son].poi]); 44 x=son; 45 } 46 else return; 47 } 48 } 49 inline void dijkstra(int x){ 50 h[tot=pos[x]=1]=(heap){x,dis[x]=0}; 51 while(tot){ 52 int now=h[1].poi; h[1]=h[tot--]; if(tot) down(1); 53 for(rg int i=last[now],to;i;i=e[i].pre) 54 if(dis[to=e[i].to]>dis[now]+log(e[i].dis)){ 55 dis[to]=dis[now]+log(e[i].dis); 56 from[to]=now; way[to]=i; 57 if(!pos[to]) h[pos[to]=++tot]=(heap){to,dis[to]}; 58 else h[pos[to]].dis=dis[to]; 59 up(pos[to]); 60 } 61 } 62 } 63 int main(){ 64 n=read(); m=read(); 65 for(rg int i=1;i<=n;i++) dis[i]=inf; 66 while(m--){ 67 int u=read(),v=read(); 68 add(u,v,read()); 69 } 70 dijkstra(1); 71 int tmp=n; 72 ans=e[way[tmp]].dis%Mod; 73 while(tmp=from[tmp]){ 74 if(tmp==1) break; 75 ans*=e[way[tmp]].dis; 76 ans%=Mod; 77 } 78 printf("%lld ",ans); 79 return 0; 80 }