https://www.luogu.org/problemnew/show/P3953
开o2过了不开o2re一个点。。。写法如题
顺便一提这道题在我校oj是a不了的因为我校土豆服务器速度奇慢1s时限
1 // luogu-judger-enable-o2 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #include<queue> 8 using namespace std; 9 const int maxn=110000; 10 int n,m,k,p; 11 struct nod{ 12 int y,v,next; 13 }e[2][maxn*2]; 14 int head[2][maxn]={}; 15 int dis[2][maxn]={}; 16 int d[maxn]={},zz[maxn]={}; 17 int mx,cnt=0,ans=0,tot=0; 18 int f[60][maxn]={}; 19 bool vis[maxn]={}; 20 queue< int >q; 21 void init(int x,int y,int v){ 22 e[0][++tot].y=y;e[0][tot].v=v;e[0][tot].next=head[0][x];head[0][x]=tot; 23 e[1][tot].y=x;e[1][tot].v=v;e[1][tot].next=head[1][y];head[1][y]=tot; 24 } 25 void SPFA(int x,int z){ 26 for(int i=1;i<=n;i++)vis[i]=0; 27 q.push(x);vis[x]=1;dis[z][x]=0; 28 int y,v,v1; 29 while(!q.empty()){ 30 x=q.front();q.pop();v=dis[z][x]; 31 for(int i=head[z][x];i;i=e[z][i].next){ 32 y=e[z][i].y;v1=e[z][i].v; 33 if(dis[z][y]>v+v1){ 34 dis[z][y]=v+v1; 35 if(!vis[y])q.push(y); 36 vis[y]=1; 37 } 38 } 39 vis[x]=0; 40 } 41 } 42 bool Topsort(){ 43 for(int i=1;i<=n;i++)d[i]=0; 44 for(int i=1;i<=n;i++){ 45 for(int j=head[0][i];j;j=e[0][j].next){ 46 if(e[0][j].v+dis[0][i]==dis[0][e[0][j].y])d[e[0][j].y]++;//按照最短路连边 47 } 48 }cnt=0; 49 for(int i=1;i<=n;i++)if(!d[i])zz[++cnt]=i; 50 for(int i=1;i<=cnt;i++){ 51 for(int j=head[0][zz[i]];j;j=e[0][j].next){ 52 if(e[0][j].v+dis[0][zz[i]]==dis[0][e[0][j].y]){ 53 d[e[0][j].y]--; 54 if(!d[e[0][j].y])zz[++cnt]=e[0][j].y; 55 } 56 } 57 } 58 for(int j=1;j<=n;j++){//如果有0边构成的环,那么这个环一定到最后也有d 59 if(d[j]&&dis[0][j]+dis[1][j]<=k+dis[0][n])return 1;//如果环在合法路上就不用dp了有无数种方案 60 }return 0; 61 } 62 void DP(){ 63 for(int i=0;i<=k;i++) 64 for(int j=0;j<=n;j++)f[i][j]=0; 65 ans=0;f[0][1]=1; 66 int y,v,x; 67 for(int i=0;i<=k;i++){ 68 for(int j=1;j<=cnt;j++){ 69 x=zz[j];if(dis[1][x]==mx)continue; 70 for(int w=head[0][x];w;w=e[0][w].next){ 71 y=e[0][w].y;v=e[0][w].v; 72 if(dis[0][x]+v==dis[0][y])f[i][y]=(f[i][y]+f[i][x])%p;//用拓扑序给f[k][i]汇总一下 73 } 74 } 75 for(int j=1;j<=n;j++){//f[k][x]往下延伸 76 x=j;if(dis[1][x]==mx)continue; 77 for(int w=head[0][x];w;w=e[0][w].next){ 78 y=e[0][w].y;v=e[0][w].v; 79 if(dis[0][x]+v!=dis[0][y]){ 80 if(i+dis[0][x]+v-dis[0][y]<=k) 81 f[i+dis[0][x]+v-dis[0][y]][y]=(f[i+dis[0][x]+v-dis[0][y]][y]+f[i][x])%p; 82 } 83 } 84 }ans=(ans+f[i][n])%p; 85 } 86 } 87 int main(){ 88 //freopen("now.in","r",stdin); 89 int T;scanf("%d",&T);mx=(int)1e8; 90 while(T-->0){ 91 scanf("%d%d%d%d",&n,&m,&k,&p); 92 for(int i=0;i<=n;i++)dis[0][i]=dis[1][i]=mx; 93 for(int i=0;i<=n;i++)head[0][i]=head[1][i]=0;tot=0; 94 int x,y,v; 95 for(int i=1;i<=m;i++){ 96 scanf("%d%d%d",&x,&y,&v);init(x,y,v); 97 } 98 SPFA(1,0);SPFA(n,1);//cout<<dis[1][1]<<dis[0][n]<<endl; 99 if(dis[1][1]==mx)printf("0 "); 100 else{ 101 if(Topsort()){ 102 printf("-1 "); 103 } 104 else{ 105 DP(); 106 printf("%d ",ans); 107 } 108 } 109 } 110 return 0; 111 }