大意:给定有向图G,求1->n的长度<=最短距离+K的路径方案数
先求起点到每个点和每个点到终点的最短路,排除掉不可能到达的点防止其干扰(dis[i]+pdis[i]>dis[n]+K)
然后每条边的边权更新为len[x->y]+dis[x]-dis[y] (走这条边浪费的时间)
现在只需要统计浪费的时间不超过K的方案
长度为0的边用拓扑序转移,长度>0的直接转移……(dp[x][j]->dp[y][j+len])
求拓扑序的时候可以顺便判一下0环
代码极烂……Orz w_yqts
#include
using namespace std;
#define inf 1000000000
#define N 500005
int ins[N];
int tot[N][60],q[N],inq[N],st,ed,dian[N],rd[N],ans;
int num,pre[N],to[N],Next[N],Next1[N],head[N],tail[N],len[N];
int dis[N],pdis[N],flag[N];
int n,m,K,p,ling,x,y,z;
inline void init()
{
num=0;
for (int i=1;i<=n;++i) head[i]=0,tail[i]=0,dis[i]=inf,pdis[i]=inf;
}
inline void add(int x,int y,int t)
{
++num;
pre[num]=x;
to[num]=y;
Next[num]=head[x];
head[x]=num;
Next1[num]=tail[y];
tail[y]=num;
len[num]=t;
}
struct node
{
int x,s;
}t;
bool operator > (node x,node y)
{
return x.s<y.s;
}
bool operator < (node x,node y)
{
return x.s>y.s;
}
priority_queue heap;
inline int read()
{
char ch=getchar();
int x=0;
while (ch<'0' || ch>'9') ch=getchar();
while ('0'<=ch && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
inline void solve()
{
scanf("%d%d%d%d",&n,&m,&K,&p);
init();
for (int i=1;i<=m;++i)
{
x=read(),y=read(),z=read();
add(x,y,z);
}
dis[1]=0;
heap.push((node){1,0});
for (int i=1;i<=n;++i) flag[i]=1;
while (!heap.empty())
{
t=heap.top();heap.pop();
while (!flag[t.x] && !heap.empty()) t=heap.top(),heap.pop();
if (!flag[t.x]) break;
flag[t.x]=0;
for (int i=head[t.x];i;i=Next[i])
if (dis[t.x]+len[i]x]+len[i];
heap.push((node){to[i],dis[to[i]]});
}
}
pdis[n]=0;
heap.push((node){n,0});
for (int i=1;i<=n;++i) flag[i]=1;
while (!heap.empty())
{
t=heap.top();heap.pop();
while (!flag[t.x] && !heap.empty()) t=heap.top(),heap.pop();
if (!flag[t.x]) break;
flag[t.x]=0;
for (int i=tail[t.x];i;i=Next1[i])
if (pdis[t.x]+len[i]x]+len[i];
heap.push((node){pre[i],pdis[pre[i]]});
}
}
//for (int i=1;i<=n;++i) cout<' ';cout<//for (int i=1;i<=n;++i) cout<' ';cout<0;
for (int i=1;i<=n;++i) dian[i]=flag[i]=1,rd[i]=0;
for (int i=1;i<=num;++i) len[i]=len[i]+dis[pre[i]]-dis[to[i]];
//cout<<"========="<for (int i=1;i<=num;++i) cout<' '<' '<"=========="<for (int i=1;i<=n;++i) if (dis[i]+pdis[i]>dis[n]+K) dian[i]=0;
for (int i=1;i<=num;++i) if (dian[to[i]] && len[i]==0 && dian[pre[i]]) flag[pre[i]]=0,++rd[to[i]];
st=0,ed=0;
for (int i=1;i<=n;++i) if (!rd[i] && dian[i] && !flag[i]) q[++ed]=i;
while (stint x=q[++st];
for (int i=head[x];i;i=Next[i])
if (len[i]==0 && dian[to[i]])
{
int y=to[i];
--rd[y];
if (!rd[y]) q[++ed]=y;
}
}
int led=ed;
for (int i=1;i<=n;++i) if (rd[i]) {ling=1;break;}
if (ling) {puts("-1");return;}
for (int j=0;j<=K;++j) for (int i=1;i<=n;++i) tot[i][j]=0;
tot[1][0]=1;
ans=0;
for (int j=0;j<=K;++j)
{
for (int i=1;i<=led;++i)
{
int x=q[i];
if (!dian[x] || !tot[x][j]) continue;
for (int k=head[x];k;k=Next[k])
if (j+len[k]<=K && !len[k])
{
tot[to[k]][j+len[k]]=(tot[to[k]][j+len[k]]+tot[x][j])%p;
}
}
for (int i=1;i<=num;++i)
if (len[i] && j+len[i]<=K)
{
tot[to[i]][j+len[i]]=(tot[to[i]][j+len[i]]+tot[pre[i]][j])%p;
}
}
for (int i=0;i<=K;++i) ans=(ans+tot[n][i])%p;
cout<int main()
{
//freopen("park.in","r",stdin);
//freopen("park.out","w",stdout);
int T;
cin>>T;
while (T--) solve();
}