[luogu P3953] [noip2017 d1t3] 逛公园
题目描述
策策同学特别喜欢逛公园。公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从$N$号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到$N$号点的最短路长为$d$,那么策策只会喜欢长度不超过$d + K$的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对$P$取模。
如果有无穷多条合法的路线,请输出−1。
输入输出格式
输入格式:
第一行包含一个整数 $T$, 代表数据组数。
接下来$T$组数据,对于每组数据: 第一行包含四个整数 $N,M,K,P$,每两个整数之间用一个空格隔开。
接下来$M$行,每行三个整数$a_i,b_i,c_i$,代表编号为$a_i,b_i$的点之间有一条权值为 $c_i$的有向边,每两个整数之间用一个空格隔开。
输出格式:
输出文件包含 $T$ 行,每行一个整数代表答案。
输入输出样例
输入样例#1: 复制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输出样例#1: 复制3 -1说明
【样例解释1】
对于第一组数据,最短路为 3。 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 为 3 条合法路径。
【测试数据与约定】
对于不同的测试点,我们约定各种参数的规模不会超过如下
测试点编号 $T$ $N$ $M$ $K$ 是否有0边 1 5 5 10 0 否 2 5 1000 2000 0 否 3 5 1000 2000 50 否 4 5 1000 2000 50 否 5 5 1000 2000 50 否 6 5 1000 2000 50 是 7 5 100000 200000 0 否 8 3 100000 200000 50 否 9 3 100000 200000 50 是 10 3 100000 200000 50 是 对于 100%的数据, $1 \le P \le 10^9,1 \le a_i,b_i \le N ,0 \le c_i \le 1000$。
数据保证:至少存在一条合法的路线。
哎,可惜了,因为一个玄学错误,而失去了a掉这题机会。
真的,我沿着完全正确的方向思考——dp,f[t][i],到i点,路径长与到i的最短路相差t的方案数。
if (t-(w-d)>=0) f[t][son[j]]+=f[t-(w-d)][i]。其中w是边权,d是dis[son[j]]-dis[i]。
当然,在考试中,我发现在d=w时会有些小差异,。要确定顺序、好啊,来个topo啊,直接抓来一棵想类似最短路树的东西,直接可以进行topo。
然后-1的判法,考场上只写了spfa直接判,没多想,其实可以根据topo排序的结果,是否合法判断一下就可以了。
但是还是wa了,为什么?
今天正好订正这题,改了一个地方:
if (t+(w-d)<=k) f[t+(w-d)][son[j]]+=f[t][i],就a掉了,否则wa30。
qwq。。。自己玩死自己。
但为什么这样就可以了呢?
我还没有想清楚啊,不知道有没有大佬能给个好的解释?
code:
%:pragma GCC optimize() #include <cstdio> #include <cstring> #include <algorithm> #define LL long long #define ms(a,x) memset(a,x,sizeof a) using namespace std; ,M=; int n,m,k,p,tot,lnk[N],nxt[M],son[M],w[M]; int tt,lk[N],nt[M],sn[M]; ],f[N],l,r; bool vis[N]; ][N],d,ans; inline int readint() { ; char ch=getchar(); ') ch=getchar(); +ch-',ch=getchar(); return x; } void adde(int x,int y,int z) { nxt[++tot]=lnk[x],lnk[x]=tot,son[tot]=y,w[tot]=z; } void addn(int x,int y) { nt[++tt]=lk[x],lk[x]=tt,sn[tt]=y; } void spfa() { ms(dis,),ms(vis,); dis[]=,q[]=,l=,r=; for (int x; l!=r; ) { l=(l+)%N,vis[x=q[l]]=; for (int j=lnk[x]; j; j=nxt[j]) { if (dis[son[j]]>dis[x]+w[j]) { dis[son[j]]=dis[x]+w[j]; )%N,vis[q[r]=son[j]]=; } } } } void topo() { ms(vis,); l=,r=; ; i<=n; ++i) ) q[++r]=i; for (int x; l<r; ) { ++l,x=q[l]; ) { --f[sn[j]]; ) q[++r]=sn[j]; } } } int main() { for (int T=readint(); T; --T) { tot=,ms(lnk,),ms(nxt,); tt=,ms(lk,),ms(nt,); n=readint(),m=readint(),k=readint(),p=readint(); ,x,y,z; i<=m; ++i) { x=readint(),y=readint(),z=readint(); adde(x,y,z); } spfa(); ms(g,),g[][]=,ms(f,); ; i<=n; ++i) for (int j=lnk[i]; j; j=nxt[j]) if (dis[son[j]]==dis[i]+w[j]) ++f[son[j]],addn(i,son[j]); topo(); if (r<n) { puts("-1"); continue; } ; t<=k; ++t) ,i; x<=n; ++x) { i=q[x]; for (int j=lnk[i]; j; j=nxt[j]) { d=dis[son[j]]-dis[i]; if (t+w[j]-d<=k) { g[t+w[j]-d][son[j]]+=g[t][i]; if (g[t+w[j]-d][son[j]]>=p) g[t+w[j]-d][son[j]]-=p; } } } ans=; ; t<=k; ++t) ans=(ans+g[t][n])%p; printf("%d\n",ans); } ; }