NOIP2017 逛公园

题目描述

策策同学特别喜欢逛公园。公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

策策每天都会去逛公园,他总是从1号点进去,从NN号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对PP取模。

如果有无穷多条合法的路线,请输出−1。

输入输出格式

输入格式:

 

第一行包含一个整数 TT, 代表数据组数。

接下来TT组数据,对于每组数据: 第一行包含四个整数 N,M,K,PN,M,K,P,每两个整数之间用一个空格隔开。

接下来MM行,每行三个整数a_i,b_i,c_iai,bi,ci,代表编号为a_i,b_iai,bi的点之间有一条权值为 c_ici的有向边,每两个整数之间用一个空格隔开。

 

输出格式:

 

输出文件包含 TT 行,每行一个整数代表答案。

 

输入输出样例

输入样例#1: 复制
2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0
输出样例#1: 复制
3
-1

说明

【样例解释1】

对于第一组数据,最短路为 3。 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 为 3 条合法路径。

【测试数据与约定】

对于不同的测试点,我们约定各种参数的规模不会超过如下

测试点编号  TT   NN   MM   KK   是否有0边
1 5 5 10 0
2 5 1000 2000 0
3 5 1000 2000 50
4 5 1000 2000 50
5 5 1000 2000 50
6 5 1000 2000 50
7 5 100000 200000 0
8 3 100000 200000 50
9 3 100000 200000 50
10 3 100000 200000 50

对于 100%的数据, 1 \le P \le 10^9,1 \le a_i,b_i \le N ,0 \le c_i \le 10001P109,1ai,biN,0ci1000。

数据保证:至少存在一条合法的路线。

首先dp很好想:f[i][j]表示到i,比最短路大j的方案数

转移可以用记忆化广搜,但效率不高

实际上转移顺序的问题可以通过拓扑排序实现

对于每一个j值(从小到大枚举),都可以用最短路径的拓扑序先对j进行转移

f[Top[]][j]+=f[i][j]

然后就可以枚举每一个点的边进行转移,因为与最短路差肯定大于j,所以不用考虑顺序:f[v][j+w+dist[u]-dist[v]]+=f[u][j]

判断无解因为是按照最短路径拓扑,所以如果有节点未出队且通过该点的最短

路<=(1,n)的最短路+k

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring> 
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 struct Node
  8 {
  9      int next,to,dis;
 10 }edge[500011];
 11 int head[2][200011],dist[2][200011],n,m,k,inf=2e8;
 12 int f[200011][55],ans,Mod,num,sum,T[500011],du[200011];
 13 bool vis[200011];
 14 void add(int x,int u,int v,int dis)
 15 {
 16     num++;
 17     edge[num].next=head[x][u];
 18     head[x][u]=num;
 19     edge[num].to=v;
 20     edge[num].dis=dis;
 21 }
 22 queue<int>Q;
 23 void SPFA(int t)
 24 {int i;
 25     for (i=1;i<=n;i++)
 26     dist[t][i]=inf,vis[i]=0;
 27     while (Q.empty()==0) Q.pop();
 28     if (t==0) Q.push(1),dist[t][1]=0;
 29     else Q.push(n),dist[t][n]=0;
 30     while (Q.empty()==0)
 31     {
 32         int u=Q.front();
 33         vis[u]=0;
 34         Q.pop();
 35         for (i=head[t][u];i;i=edge[i].next)
 36         {
 37             int v=edge[i].to;
 38             if (dist[t][u]+edge[i].dis<dist[t][v])
 39             {
 40                 dist[t][v]=dist[t][u]+edge[i].dis;
 41                 if (vis[v]==0) vis[v]=1,Q.push(v); 
 42             }
 43         }
 44     }
 45 }
 46 void Top()
 47 {int i,j;
 48 while (Q.empty()==0) Q.pop();
 49 for (i=0;i<=n;i++)du[i]=0;
 50     for (i=1;i<=n;i++)
 51     {
 52         for (j=head[0][i];j;j=edge[j].next)
 53         if (dist[0][i]+edge[j].dis==dist[0][edge[j].to]) du[edge[j].to]++;
 54     }
 55     for (i=1;i<=n;i++)
 56     if (du[i]==0) Q.push(i),sum++,T[sum]=i;
 57     while (Q.empty()==0)
 58     {
 59         int u=Q.front();
 60         Q.pop();
 61         for (i=head[0][u];i;i=edge[i].next)
 62         {
 63             int v=edge[i].to;
 64             if (dist[0][v]==dist[0][u]+edge[i].dis)
 65             {
 66                 du[v]--;
 67                 if (du[v]==0) Q.push(v),sum++,T[sum]=v;
 68             }
 69         }
 70     }
 71 }
 72 void DP()
 73 {int i,j,l;
 74     f[1][0]=1;
 75     for (i=0;i<=k;i++)
 76     {
 77         for (j=1;j<=sum;j++)
 78         {
 79             int u=T[j];
 80             if (f[u][i]==0) continue;
 81             for (l=head[0][u];l;l=edge[l].next)
 82             {
 83                 int v=edge[l].to;
 84                 if (dist[0][v]==dist[0][u]+edge[l].dis)
 85                 f[v][i]=(f[v][i]+f[u][i])%Mod;
 86             }
 87         }
 88         for (j=1;j<=n;j++)
 89         if (f[j][i])
 90         for (l=head[0][j];l;l=edge[l].next)
 91         {
 92             int v=edge[l].to;
 93             if (dist[0][v]!=dist[0][j]+edge[l].dis)
 94             if (dist[0][j]+edge[l].dis-dist[0][v]+i<=k)
 95             {
 96                 f[v][dist[0][j]+edge[l].dis-dist[0][v]+i]=(f[v][dist[0][j]+edge[l].dis-dist[0][v]+i]+f[j][i])%Mod;
 97             }
 98         }
 99     }
100     ans=0;
101     for (i=0;i<=k;i++)
102     ans=(ans+f[n][i])%Mod;
103     printf("%d\n",ans);
104 }
105 int main()
106 {int T,i,j,u,v,d,flag;
107  cin>>T;
108      while (T--)
109      {
110          cin>>n>>m>>k>>Mod;
111          num=0;
112          sum=0;
113          for (i=0;i<=200000;i++)
114          head[0][i]=head[1][i]=0;
115          for (i=0;i<=n;i++)
116          for (j=0;j<=k;j++)
117          f[i][j]=0;
118         for (i=1;i<=m;i++)
119         {
120             scanf("%d%d%d",&u,&v,&d);
121             add(0,u,v,d);add(1,v,u,d);
122         } 
123         SPFA(0);SPFA(1);
124         Top();
125         flag=0;
126         for (i=1;i<=n;i++)
127         if (du[i]&&dist[0][i]+dist[1][i]<=dist[0][n]+k)
128         {
129             printf("-1\n");
130             flag=1;
131             break;
132         }
133         if (flag==0)
134             DP();
135      }
136 } 

 

posted @ 2017-12-11 13:50  Z-Y-Y-S  阅读(307)  评论(0编辑  收藏  举报