P3953 [NOIP2017 提高组] 逛公园

// https://www.luogu.com.cn/problem/P3953
/*
dis(1,n)+k>=dist(1,n) 的方案数 30-最短路计数 <- dp 70-没有零环 自然的设 f[u][k] dist(1,u)==dis(1,u)+k 方案数 dis(1,u)+k+edge(u,v)==dis(1,v)+x x=dis(1,u)+k+edge(u,v)-dis(1,v) k=dis(1,v)+x-dis(1,u)-edge(u,v) f[v][x]=sum(f[u][ k=dis(1,v)+x-dis(1,u)-edge(u,v)] ) 由于 正向图不一定能走到 n点 所以建反图 f[u][k] dist(u,n)==dis(u,n)+k 方案数 即n-u的合法方案数 dis(u,n)+k-edge(u,v)==dis(n,v)+x k=dis(n,v)+x-dis(n,u)+edge(u,v) x=dis(u,n)+k-edge(u,v)-dis(n,v) f[u][k]=sum(f[v][x=dis(u,n)+k-edge(u,v)-dis(n,v)]) f[n][0]=1 100: 有零环 有无数条路径 检查是否已经入栈 */ /* 2 5 7 2 10 1 2 1 2 4 0 4 5 2 2 3 2 3 4 1 3 5 2 1 5 3 2 2 0 10 1 2 0 2 1 0 3 -1 */ #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<string.h> //#include<queue> //#include<vector> #include<bits/stdc++.h> #define ll long long #define ddd printf("-----------------------\n"); using namespace std; const int maxn=2e5 +10; const int mod=998244353; const int inf=0x3f3f3f3f; int n,m,k,p; int head1[maxn],tot1,tot2,head2[maxn],to1[maxn<<1],to2[maxn<<1],nxt1[maxn<<1],nxt2[maxn<<1],w1[maxn<<1],w2[maxn<<1]; int f[maxn>>1][55],ins[maxn>>1][60],dis[maxn],vis[maxn],ans,flag; void add1(int a,int b,int val){ to1[++tot1]=b,nxt1[tot1]=head1[a],head1[a]=tot1,w1[tot1]=val; } void add2(int a,int b,int val){ to2[++tot2]=b,nxt2[tot2]=head2[a],head2[a]=tot2,w2[tot2]=val; } void spfa() { memset(vis,0,sizeof(vis)); memset(dis,inf,sizeof(dis)); queue<int> q; q.push(n),dis[n]=0,vis[n]=1; while(q.size()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head2[u];i;i=nxt2[i]) { int v=to2[i]; if(dis[v]>dis[u]+w2[i]) { dis[v]=dis[u]+w1[i]; if(vis[v]==0) q.push(v),vis[v]=1; } } } } int dfs(int u,int know) { if(ins[u][know]){ flag=1; return 0;}//!!!!!!!!!!!!!!!! if(f[u][know]) return f[u][know]; ins[u][know]=1; int sum=0; for(int i=head1[u];i;i=nxt1[i]) { int v=to1[i]; int tmp=know-(w1[i]+dis[v]-dis[u]); if(tmp<0||tmp>k) continue;//!!!!!!!!!!!!!!!!!!!!!! sum=(sum+dfs(v,tmp))%p; if(flag) return 0; } if(u==n&&know==0) sum=1; ins[u][know]=0; return f[u][know]=sum; } int main() { ios::sync_with_stdio(false); int T;cin>>T; while(T--) { memset(head1,0,sizeof(head1)),memset(head2,0,sizeof(head2)); tot1=0,tot2=0; memset(to1,0,sizeof(to1)),memset(to2,0,sizeof(to2)); memset(w1,0,sizeof(w1)),memset(w2,0,sizeof(w2)); memset(nxt1,0,sizeof(nxt1)),memset(nxt2,0,sizeof(nxt2)); memset(ins,0,sizeof(ins)),memset(f,0,sizeof(f)); flag=0,ans=0; cin>>n>>m>>k>>p; for(int i=1;i<=m;i++){ int a,b,c;cin>>a>>b>>c; add1(a,b,c),add2(b,a,c); } spfa(); for(int i=0;i<=k;i++) ans=(ans+dfs(1,i))%p; if(flag==1) cout<<"-1\n"; else cout<<ans<<'\n'; } return 0; }

 

posted @ 2023-10-28 07:33  JMXZ  阅读(13)  评论(0)    收藏  举报