[luogu P3953] [noip2017 d1t3] 逛公园

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu P3953] [noip2017 d1t3] 逛公园相关的知识,希望对你有一定的参考价值。

[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:

技术分享图片
 1 %:pragma GCC optimize(2)
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define LL long long
 6 #define ms(a,x) memset(a,x,sizeof a)
 7 using namespace std;
 8 const int N=100005,M=200005;
 9 int n,m,k,p,tot,lnk[N],nxt[M],son[M],w[M];
10 int tt,lk[N],nt[M],sn[M];
11 int dis[N],q[N*2],f[N],l,r; bool vis[N];
12 int g[51][N],d,ans;
13 inline int readint() {
14     int x=0; char ch=getchar();
15     while (ch<0||ch>9) ch=getchar();
16     while (ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
17     return x;
18 }
19 void adde(int x,int y,int z) {
20     nxt[++tot]=lnk[x],lnk[x]=tot,son[tot]=y,w[tot]=z;
21 }
22 void addn(int x,int y) {
23     nt[++tt]=lk[x],lk[x]=tt,sn[tt]=y;
24 }
25 void spfa() {
26     ms(dis,30),ms(vis,0);
27     dis[1]=0,q[1]=1,l=0,r=1;
28     for (int x; l!=r; ) {
29         l=(l+1)%N,vis[x=q[l]]=0;
30         for (int j=lnk[x]; j; j=nxt[j]) {
31             if (dis[son[j]]>dis[x]+w[j]) {
32                 dis[son[j]]=dis[x]+w[j];
33                 if (!vis[son[j]]) r=(r+1)%N,vis[q[r]=son[j]]=1;
34             }
35         }
36     }
37 }
38 void topo() {
39     ms(vis,0);
40     l=0,r=0;
41     for (int i=1; i<=n; ++i) if (f[i]==0) q[++r]=i;
42     for (int x; l<r; ) {
43         ++l,x=q[l];
44         for (int j=lk[x]; j; j=nt[j]) if (f[sn[j]]>0) {
45             --f[sn[j]];
46             if (f[sn[j]]==0) q[++r]=sn[j];
47         }
48     }
49 }
50 int main() {
51     for (int T=readint(); T; --T) {
52         tot=0,ms(lnk,0),ms(nxt,0);
53         tt=0,ms(lk,0),ms(nt,0);
54         n=readint(),m=readint(),k=readint(),p=readint();
55         for (int i=1,x,y,z; i<=m; ++i) {
56             x=readint(),y=readint(),z=readint();
57             adde(x,y,z);
58         }
59         spfa();
60         ms(g,0),g[0][1]=1,ms(f,0);
61         for (int i=1; i<=n; ++i)
62         for (int j=lnk[i]; j; j=nxt[j])
63         if (dis[son[j]]==dis[i]+w[j]) ++f[son[j]],addn(i,son[j]);
64         topo();
65         if (r<n) {
66             puts("-1");
67             continue;
68         }
69         for (int t=0; t<=k; ++t)
70         for (int x=1,i; x<=n; ++x) {
71             i=q[x];
72             for (int j=lnk[i]; j; j=nxt[j]) {
73                 d=dis[son[j]]-dis[i];
74                 if (t+w[j]-d<=k) {
75                     g[t+w[j]-d][son[j]]+=g[t][i];
76                     if (g[t+w[j]-d][son[j]]>=p) g[t+w[j]-d][son[j]]-=p;
77                 }
78             }
79         }
80         ans=0;
81         for (int t=0; t<=k; ++t) ans=(ans+g[t][n])%p;
82         printf("%d\n",ans);
83     }
84     return 0;
85 }
View Code

以上是关于[luogu P3953] [noip2017 d1t3] 逛公园的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P3953 [NOIP2017 提高组] 逛公园(最短路,记忆化搜索)

P3953 NOIP2017 d1t3 逛公园

Luogu P3953 逛公园(最短路+记忆化搜索)

[Luogu P3953] 逛公园 (最短路+拓扑排序+DP)

NOIP2017 普及 luogu3955 图书管理员

noip2017普及 luogu3954 成绩