https://www.luogu.org/problemnew/show/P3953
策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从N号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到N号点的最短路长为d,那么策策只会喜欢长度不超过d + K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对P取模。
如果有无穷多条合法的路线,请输出-1。
看到这道题首先想到的是肯定要使用最短路算法求解。30分做法只需跑一边spfa,因为k=0,所以之后最短路计数即可;这道题看到k<=50,应该能想到是一道与k有关的dp,那么状态可以设为f(i,k),表示在i这个点还能多走k长度。建图时用正反都建图,先正向跑堆优化dijkstra,计算出每一个点到1的最短距离dis数组。因为不是每个点都能到达终点,这样再反向跑spfa,计算出哪些点与终点n联通即可,即used数组。再dfs中,使用vis数组判断是否有0环。这道题就这样被解决了。
#include
#include
#include
#include
#include
using namespace std;
int inline read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int N=100050,M=200050,K=65,inf=0x3f;
int T,n,m,k,p,cntz,cntn;
int headz[N],headn[N],ans[N][K],dis[N];
bool used[N],vis[N][K];
struct node2
{
int u,d;
bool operator < (const node2& rhs)const{
return d>rhs.d;
}
};
priority_queue q;
queue f;
struct node
{
int next,to,w;
}ez[M],en[M];
void addz(int x,int y,int z)
{
ez[++cntz].next=headz[x];
ez[cntz].to=y;
ez[cntz].w=z;
headz[x]=cntz;
}
void addn(int x,int y,int z)
{
en[++cntn].next=headn[x];
en[cntn].to=y;
en[cntn].w=z;
headn[x]=cntn;
}
void zheng_dijkstra()
{
dis[1]=0;
q.push((node2){1,0});
while(!q.empty()){
node2 now=q.top();q.pop();
int u=now.u,d=now.d;
if(d!=dis[u]) continue;
for(int i=headz[u];i;i=ez[i].next){
int v=ez[i].to;
if(dis[v]>dis[u]+ez[i].w){
dis[v]=dis[u]+ez[i].w;
q.push((node2){v,dis[v]});
}
}
}
return;
}
void ni_spfa()
{
f.push(n);
used[n]=1;
while(!f.empty()){
int u=f.front();f.pop();
for(int i=headn[u];i;i=en[i].next){
int v=en[i].to;
if(!used[v]){
used[v]=1;
f.push(v);
}
}
}
return;
}
int dfs(int a,int b)
{
if(b<0) return 0;
else if(vis[a][b]==1) return -inf;
else if(ans[a][b]!=-1) return ans[a][b];
else{
vis[a][b]=1;
int key=0;
if(a==n){
key++;
}
for(int i=headz[a];i;i=ez[i].next){
int v=ez[i].to,w=ez[i].w,d=dis[v]-dis[a];
if(!used[v]) continue;
int sum=dfs(v,b-(w-d));
if(sum==-inf){
return -inf;
}
else{
key=(key+sum)%p;
}
}
vis[a][b]=0;
ans[a][b]=key%p;
return key;
}
}
void init()
{
memset(ez,0,sizeof(ez));
memset(en,0,sizeof(en));
memset(headz,0,sizeof(headz));
memset(headn,0,sizeof(headn));
memset(dis,inf,sizeof(dis));
memset(used,false,sizeof(used));
memset(vis,false,sizeof(vis));
memset(ans,-1,sizeof(ans));
}
int main()
{
T=read();
while(T--){
init();
n=read();m=read();k=read();p=read();
for(int i=1;i<=m;++i){
int x,y,z;
x=read();y=read();z=read();
addz(x,y,z);addn(y,x,z);
}
zheng_dijkstra();
ni_spfa();
int tot=dfs(1,k);
if(tot==-inf){
cout<<-1<