题目描述
策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从N号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到N号点的最短路长为d,那么策策只会喜欢长度不超过d+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对P取模。
如果有无穷多条合法的路线,请输出-1。
解:
思路很好想
定义 f[i][j]表示以i号点为结尾的 距离起点距离为 dis+j j是偏量dis是最短距离 的方案数
画个图可以知道 f[i][j]=(sum) $f[u][j-(dis[u]+le[s]-dis[i])] $ 可以利用记忆化搜索
如果有0环则无解
注意到我们tarjan求的是强连通分量 不是强连通子图
所以我们可以建立边权为0的图求tarjan 求到的环一定满足充要条件
注意判断这个环是否满足条件
code:
//
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxnn 100005
#define maxn 500005
ll f[maxnn][55];
#define inf 10000000
int T;
ll n,m,k,p;
int is[maxnn];
int ty=0;
int book[maxnn][55];
int dfn[maxnn],low[maxnn],vii,instack[maxnn];
int las[maxn],en[maxn],le[maxn],tot,nex[maxn];
int zlas[maxn],zen[maxn],zle[maxn],ztot,znex[maxn];
int las1[maxn],en1[maxn],le1[maxn],tot1,nex1[maxn];
ll dis[maxnn];
ll dis1[maxnn];
int mark[maxnn];
int ttt[maxnn];
int co[maxnn];
int sec;
int belong[maxnn];
int mask[maxnn];
stack<int > S;
void tarjan(int u) {
int v;
mask[u]=1;
dfn[u]=low[u]=++vii;
instack[u]=1;
S.push(u);
for(int i=zlas[u]; i; i=znex[i]) {
int y=zen[i];
if(!dfn[y]) {
tarjan(y);
low[u]=min(low[u],low[y]);
} else if(dfn[y]&&instack[y]) {
low[u]=min(low[u],dfn[y]);
}
}
if(dfn[u]==low[u]) {
sec++;
do {
v=S.top();
S.pop();
belong[v]=sec;
if(dis[v]+dis1[v]<=dis[n]+k)
{
is[sec]=1;
}
ttt[sec]++;
instack[v]=0;
} while(v!=u);
}
if(ttt[sec]>=2&&is[sec])
{
ty=1;
}
}
queue<int > Q;
void spfa() {
for(int i=1; i<=n; i++) {
mark[i]=0;
dis[i]=inf;
}
dis[1]=0;
Q.push(1);
while(Q.size()) {
int v=Q.front();
mark[v]=0;
Q.pop();
for(int i=las1[v]; i; i=nex1[i]) {
int u=en1[i];
if(dis[u]>dis[v]+le1[i]) {
dis[u]=dis[v]+le1[i];
if(!mark[u]) {
Q.push(u);
}
}
}
}
}
void spfa1() {
for(int i=1; i<=n; i++) {
mark[i]=0;
dis1[i]=inf;
}
dis1[n]=0;
Q.push(n);
while(Q.size()) {
int v=Q.front();
mark[v]=0;
Q.pop();
for(int i=las[v]; i; i=nex[i]) {
int u=en[i];
if(dis1[u]>dis1[v]+le[i]) {
dis1[u]=dis1[v]+le[i];
if(!mark[u]) {
Q.push(u);
}
}
}
}
}
void zadd(int a,int b,int c) {
zen[++ztot]=b;
znex[ztot]=zlas[a];
zlas[a]=ztot;
zle[ztot]=c;
}
void add1(int a,int b,int c) {
en1[++tot1]=b;
nex1[tot1]=las1[a];
las1[a]=tot1;
le1[tot1]=c;
}
void add(int a,int b,int c) {
en[++tot]=b;
nex[tot]=las[a];
las[a]=tot;
le[tot]=c;
}
ll dfs(int v,ll k) {
if(~f[v][k]) return f[v][k];
if(v==1)
{
if(k==0)
return 1;
}
ll ans=0;
for(int i=las[v]; i; i=nex[i]) {
int u=en[i];
if(k-(dis[u]+1LL*le[i]-dis[v])>=0)
ans=(ans+dfs(u,1LL*k-(dis[u]+1LL*le[i]-dis[v])))%p;
}
f[v][k]=ans%p;
return f[v][k];
}
void clear()
{
ty=0;
memset(is,0,sizeof(is));
while(S.size()) S.pop();
memset(mark,0,sizeof(mark));
memset(f,-1,sizeof(f));
memset(book,0,sizeof(book));
memset(las1,0,sizeof(las1));
memset(zlas,0,sizeof(zlas));
memset(las,0,sizeof(las));
memset(en1,0,sizeof(en1));
memset(zen,0,sizeof(zen));
memset(en,0,sizeof(en));
memset(nex1,0,sizeof(nex1));
memset(nex,0,sizeof(nex));
memset(znex,0,sizeof(znex));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(le,0,sizeof(le));
memset(le1,0,sizeof(le1));
memset(instack,0,sizeof(instack));
memset(mask,0,sizeof(mask));
memset(belong,0,sizeof(belong));
memset(co,0,sizeof(co));
memset(ttt,0,sizeof(ttt));
ztot=0;
}
int main() {
freopen("tes","r",stdin);
freopen("anss","w",stdout);
cin>>T;
while(T--) {
clear();
sec=0;
tot1=0;
vii=0;
tot=0;
int a,b,c;
cin>>n>>m>>k>>p;
for(int i=1; i<=m; i++) {
cin>>a>>b>>c;
add1(a,b,c);
add(b,a,c);
if(c==0)
{
zadd(a,b,c);
}
}
spfa();
spfa1();
ll ans=0;
for(int i=1; i<=n; i++)
if(!mask[i]) tarjan(i);
if(ty)
{
puts("-1");
continue;
}
for(int i=0;i<=k;i++)
ans=(ans+dfs(n,i))%p;
printf("%lld
",ans%p);
}
}