https://www.luogu.org/problemnew/show/P3953
第一反应,设计状态f[x][res]表示到达x点,到终点还能比最短路多走res距离的方案数。
转移时枚举下一个点,记忆化搜索。
但是这样是不对的,会有不能访问的点。
所以应该从终点开始进行记忆化搜索,建反图就可以了。
找0环,本质就是是否存在一个点,两次访问的时候res都相同,可以用一个桶记录一下。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int MAXN=200005; const int INF=1<<29; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } struct Edge{ int next,to,w; }e[MAXN],e2[MAXN]; int head[MAXN],ecnt; inline void add(int x,int y,int w){ e[++ecnt].next = head[x]; e[ecnt].to = y; e[ecnt].w = w; head[x] = ecnt; } int head2[MAXN],ecnt2; inline void add2(int x,int y,int w){ e2[++ecnt2].next = head2[x]; e2[ecnt2].to = y; e2[ecnt2].w = w; head2[x] = ecnt2; } int n,m,mod,num; struct Node{ int id,w; Node(int x=0,int y=0){id=x;w=y;} bool operator<(const Node &rhs) const { return w>rhs.w; } }; int dis[MAXN],vis[MAXN]; priority_queue<Node>Q; void dij(){ while(!Q.empty()) Q.pop(); for(int i=0;i<=n;i++) dis[i]=INF; memset(vis,0,sizeof(vis)); dis[n]=0; for(int i=1;i<=n;i++){Q.push(Node(i,dis[i]));} for(int i=1;i<=n;i++){ int mn,mnid; Node tmp; do{ tmp=Q.top(); Q.pop(); }while(vis[tmp.id]); mn=tmp.w;mnid=tmp.id; vis[mnid]=1; for(int j=head[mnid];j;j=e[j].next){ int v=e[j].to,w=e[j].w; if(dis[v]>mn+w){ dis[v]=mn+w; Q.push(Node(v,dis[v])); } } } } int f[MAXN][64],ins[MAXN][64]; bool flag=0; int dfs(int x,int res){ if(ins[x][res]) return flag=1,0; if(flag) return 0; if(~f[x][res]) return f[x][res]; ins[x][res]=1; int &ret=f[x][res]=0; for(int i=head2[x];i;i=e2[i].next){ int v=e2[i].to; if(dis[v]==INF) continue; int tmp=res-(e2[i].w-dis[x]+dis[v]); if(tmp<0||tmp>num) continue; ret+=dfs(v,tmp); ret%=mod; if(flag) return 0; } ins[x][res]=0; if(x==n&&res==0) ret++; return ret%mod; } void init(){ memset(head,0,sizeof(head)); memset(e,0,sizeof(e)); ecnt=0;flag=0; memset(head2,0,sizeof(head2)); memset(e2,0,sizeof(e2)); ecnt2=0; memset(ins,0,sizeof(ins)); memset(f,-1,sizeof(f)); } int solve(){ init(); n=rd();m=rd();num=rd();mod=rd(); int x,y,w; for(int i=1;i<=m;i++){ x=rd();y=rd();w=rd(); add(y,x,w);add2(x,y,w); } dij(); long long ans=0; for(int i=0;i<=num;i++) { memset(ins,0,sizeof(ins)); ans+=1ll*dfs(1,i)%mod; ans%=mod;//! } if(flag) return puts("-1"),0; printf("%lld\n",ans); } int main(){ int T; T=rd(); while(T--) solve(); return 0; }