学习了大佬题解。根据大佬的讲解,把对应部分分的代码打到一起了。(有点臃肿)
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1e5+10,M=2e5+10;
#define re register
int tot,t,n,m,k,p,hd[N],vis[N],hdn[N],totn,id[N],idx[N];
int cnt[N],f[N][55],ans,deg[N],hd0[N],tot0,q[N];
ll dis[N],disn[N];
inline int read()
{
int s=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*f;
}
struct Edge{
int v,nx;ll w;
}e[M],en[M];
struct node{
int u;ll w;
node(){}
node(int _u,ll _w):u(_u),w(_w){}
bool operator <(const node&rhs)const{
return w>rhs.w;}
};
namespace pts30{
void add(int u,int v,ll w)
{
e[tot].v=v;
e[tot].nx=hd[u];
e[tot].w=w;
hd[u]=tot++;
}
void dijkstra()
{
memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis));
priority_queue<node>q;dis[1]=0;q.push(node(1,0));cnt[1]=1;
while(q.size())
{
int u=q.top().u;q.pop();vis[u]=0;
for(int i=hd[u];~i;i=e[i].nx)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;cnt[v]=cnt[u];
if(!vis[v])vis[v]=1,q.push(node(v,dis[v]));
}
else if(dis[v]==dis[u]+e[i].w)
{
cnt[v]+=cnt[u];
if(cnt[v]>=p)cnt[v]-=p;
}
}
}
printf("%d\n",cnt[n]%p);
}
void solve()
{
using namespace pts30;
t=read();
while(t--)
{
memset(hd,-1,sizeof(hd));tot=0;
n=read();m=read();k=read();p=read();
int u,v;ll w;
for(int i=1;i<=m;i++)
u=read(),v=read(),w=read(),add(u,v,w);
dijkstra();
}
}
}
namespace pts70{
inline void add(int u,int v,ll w)
{
e[tot].v=v;
e[tot].nx=hd[u];
e[tot].w=w;
hd[u]=tot++;
}
bool cmp(const int &a,const int &b)
{
return dis[a]<dis[b];
}
void dijkstra()
{
memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis));
priority_queue<node>q;dis[1]=0;q.push(node(1,0));
while(q.size())
{
int u=q.top().u;q.pop();vis[u]=0;
for(int i=hd[u];~i;i=e[i].nx)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(!vis[v])vis[v]=1,q.push(node(v,dis[v]));
}
}
}
}
void solve()
{
using namespace pts70;
t=read();
while(t--)
{
memset(hd,-1,sizeof(hd));tot=0;
memset(hdn,-1,sizeof(hdn));totn=0;
memset(f,0,sizeof(f));ans=0;
n=read();m=read();k=read();p=read();
int u,v;ll w;
for(int i=1;i<=m;i++)
u=read(),v=read(),w=read(),add(u,v,w);
dijkstra();
for(int i=1;i<=n;i++)id[i]=i;
sort(id+1,id+n+1,pts70::cmp);
f[1][0]=1;
for(int j=0;j<=k;j++)
for(int i=1;i<=n;i++)
{
int u=id[i];
for(int o=hd[u];~o;o=e[o].nx)
{
int v=e[o].v;ll w=e[o].w;
if(dis[u]+j+w-dis[v]<=k)
{
f[v][dis[u]+j+w-dis[v]]+=f[u][j];
if(f[v][dis[u]+j+w-dis[v]]>=p)f[v][dis[u]+j+w-dis[v]]-=p;
}
}
}
for(int j=0;j<=k;j++)
{
ans+=f[n][j];if(ans>=p)ans-=p;
}
printf("%d\n",ans);
}
}
}
namespace AC{
struct Edge0{
int v,nx;
}e0[M];
inline void add(int u,int v,ll w)
{
e[tot].v=v;
e[tot].nx=hd[u];
e[tot].w=w;
hd[u]=tot++;
}
inline void addn(int u,int v,ll w)
{
en[totn].v=v;
en[totn].nx=hdn[u];
en[totn].w=w;
hdn[u]=totn++;
}
inline void add0(int u,int v)
{
e0[tot0].v=v;
e0[tot0].nx=hd0[u];
hd0[u]=tot0++;
}
inline void dijkstran()
{
memset(disn,0x7f,sizeof(disn));memset(vis,0,sizeof(vis));
priority_queue<node>q;disn[1]=0;q.push(node(1,0));
while(q.size())
{
re int u=q.top().u;q.pop();vis[u]=0;
for(re int i=hdn[u];~i;i=en[i].nx)
{
re int v=en[i].v;
if(disn[v]>disn[u]+en[i].w)
{
disn[v]=disn[u]+en[i].w;
if(!vis[v])vis[v]=1,q.push(node(v,disn[v]));
}
}
}
}
inline void dijkstra()
{
memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis));
priority_queue<node>q;dis[1]=0;q.push(node(1,0));
while(q.size())
{
re int u=q.top().u;q.pop();vis[u]=0;
for(re int i=hd[u];~i;i=e[i].nx)
{
re int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(!vis[v])vis[v]=1,q.push(node(v,dis[v]));
}
}
}
}
bool toposort()
{
re int h=1,t=0;
for(re int i=1;i<=n;i++)
if(!deg[i])q[++t]=i;
while(h<=t)
{
re int u=q[h++];
for(re int i=hd0[u];~i;i=e0[i].nx)
{
re int v=e0[i].v;
if(--deg[v]==0)q[++t]=v;
}
}
for(re int i=1;i<=n;i++)id[q[i]]=i;
for(re int i=1;i<=n;i++)
if(deg[i]&&dis[i]+disn[i]-dis[n]<=k)return true;
return false;
}
inline bool cmp(const int &a,const int &b)
{
return dis[a]<dis[b]||(dis[a]==dis[b]&&id[a]<id[b]);
}
inline void solve()
{
using namespace AC;
t=read();
while(t--)
{
memset(hd,-1,sizeof(hd));tot=0;
memset(hdn,-1,sizeof(hdn));totn=0;
memset(hd0,-1,sizeof(hd0));tot0=0;
memset(deg,0,sizeof(deg));memset(f,0,sizeof(f));ans=0;
n=read();m=read();k=read();p=read();
int u,v,w;
for(re int i=1;i<=m;i++)
{
u=read();v=read();w=read();add(u,v,w);addn(v,u,w);
if(!w)add0(u,v),deg[v]++;
}
dijkstra();dijkstran();
if(toposort()){puts("-1");continue;}
f[1][0]=1;
for(re int i=1;i<=n;i++)idx[i]=i;sort(idx+1,idx+n+1,cmp);
for(re int j=0;j<=k;j++)
for(re int i=1;i<=n;i++)
{
re int u=idx[i];
for(re int o=hd[u];~o;o=e[o].nx)
{
re int v=e[o].v;ll w=e[o].w;
if(dis[u]+w+j-dis[v]<=k)
{
f[v][dis[u]+w+j-dis[v]]+=f[u][j];
if(f[v][dis[u]+w+j-dis[v]]>=p)f[v][dis[u]+w+j-dis[v]]-=p;
}
}
}
for(re int i=0;i<=k;i++)
{
ans+=f[n][i];
if(ans>=p)ans-=p;
}
printf("%d\n",ans);
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//pts30::solve();
//pts70::solve();
AC::solve();
return 0;
}
总结
首先看到路径数,想能不能DP转移,然后通过求出的最短路按照拓扑序进行转移,还得判断0环。