Description

策策同学特别喜欢逛公园。公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

策策每天都会去逛公园,他总是从1号点进去,从$N$号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到$N$号点的最短路长为$d$,那么策策只会喜欢长度不超过$d + K$的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对$P$取模。

如果有无穷多条合法的路线,请输出−1。

Input

第一行包含一个整数 $T$, 代表数据组数。

接下来$T$组数据,对于每组数据: 第一行包含四个整数 $N,M,K,P$,每两个整数之间用一个空格隔开。

接下来$M$行,每行三个整数$a_i,b_i,c_i$,代表编号为$a_i,b_i$的点之间有一条权值为 $c_i$的有向边,每两个整数之间用一个空格隔开。

Output

输出文件包含 $T$ 行,每行一个整数代表答案。

Sample Input

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

Sample Output

3
-1

Hint

【样例解释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$。

数据保证:至少存在一条合法的路线。

题解(转载)

->原文地址<-

  • 这题如果直接$DP$的话,会发现有后效性,则会重复统计答案。
  • 但看到 $k≤50$ ,很小,于是我们考虑拆点。
  • 先做一次 $SPFA$,设 $1$ 到 $i$ 号点的最短路为 $dist1[i]$ 。
  • 之后把每个点拆成 $k+1$ 个点,分别对应到这个点时的路径长 $j-dist1[i]$ 的值。
  • 由于这个值的范围只在 $[0,k]$ 之间,
  • 那么我们对于开始时的有向边的两个点拆点,并进行进行连接。
  • 这样我们就构成了一个拓扑图,跑一遍拓扑排序即可。
  • 当跑完后发现并没有遍历所有点,则直接输出 $-1$ 即可。
  • 而且这题还要卡卡常,发现连边时连接了很多无用点,拖慢了拓扑排序的速度。
  • 于是我们考虑倒着做一遍 $SPFA$ (从 $n$ 开始),设 $n$ 到 $i$ 号点的最短路为 $dist2[i]$ 。
  • 当一个点 $dist1[u[i]]+dist2[v[i]]>dist1[n]+k$ 时,说明这个点就没用了,不需要从它连边出去。
  • 时间复杂度 $O(T*M*K)$ 。
 //Is is made by Awson on 2017.12.16
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define getnode(x, y) (((x)-1)*(k+1)+(y))
using namespace std;
const int N = ;
const int M = ;
const int K = ;
int read() {
int sum = ;
char ch = getchar();
while (ch < '' || ch > '') ch = getchar();
while (ch >= '' && ch <= '') sum = (sum<<)+(sum<<)+ch-'', ch = getchar();
return sum;
} int n, m, p, k, u[M+], v[M+], c[M+];
struct tt {
int to, next, cost;
}edge[(M*K<<)+];
int path[(N*K<<)+], top, path2[N+];
int dist[N+][];
bool vis[N+];
int Q[(N*K<<)+], head, tail;
int ans[(N*K<<)+], in[(N*K<<)+];
void add(int u, int v, int c) {
edge[++top].to = v;
edge[top].cost = c;
edge[top].next = path[u];
path[u] = top;
}
void add2(int u, int v, int c) {
edge[++top].to = v;
edge[top].cost = c;
edge[top].next = path2[u];
path2[u] = top;
}
void SPFA(int u, int t) {
dist[u][t] = ;
memset(vis, , sizeof(vis)); vis[u] = ;
Q[head = tail = ] = u; tail++;
while (head < tail) {
int u = Q[head]; ++head, vis[u] = ;
for (int i = path2[u]; i; i = edge[i].next)
if (dist[edge[i].to][t] > dist[u][t]+edge[i].cost) {
dist[edge[i].to][t] = dist[u][t]+edge[i].cost;
if (!vis[edge[i].to]) {
vis[edge[i].to] = ; Q[tail] = edge[i].to, ++tail;
}
}
}
}
void topsort() {
memset(ans, , sizeof(ans)); ans[] = ;
int MAX = getnode(n, k), sum = ; head = tail = ;
for (int i = ; i <= MAX; ++i) if (!in[i]) Q[tail] = i, ++tail;
while (head < tail) {
int u = Q[head]; ++head, ++sum;
for (int i = path[u]; i; i = edge[i].next) {
--in[edge[i].to]; ans[edge[i].to] = (ans[edge[i].to]+ans[u])%p;
if (!in[edge[i].to]) Q[tail] = edge[i].to, ++tail;
}
}
if (MAX+ != sum) {
printf("-1\n"); return;
}
int cnt = ;
for (int i = ; i <= k; i++)
cnt = (cnt+ans[getnode(n, i)])%p;
printf("%d\n", cnt);
} void work() {
n = read(), m = read(), k = read(), p = read();
memset(dist, /, sizeof(dist));
memset(path2, top = , sizeof(path2));
for (int i = ; i <= m; i++) {
u[i] = read(), v[i] = read(), c[i] = read();
add2(u[i], v[i], c[i]);
}
SPFA(, );
memset(path2, top = , sizeof(path2));
for (int i = ; i <= m; i++) add2(v[i], u[i], c[i]);
SPFA(n, );
memset(path, top = , sizeof(path));
memset(in, , sizeof(in));
for (int i = ; i <= m; i++) {
int a = u[i], b = v[i], d = c[i];
if (d <= dist[b][]-dist[a][]+k) {
int delta = d-(dist[b][]-dist[a][]), basea = getnode(a, ), baseb = getnode(b, delta);
for (int j = ; j <= k-delta && dist[a][]+dist[b][]+d+j <= dist[n][]+k; j++) {
add(basea+j, baseb+j, );
in[baseb+j]++;
}
}
}
topsort();
}
int main() {
int t; cin >> t;
while (t--) work();
return ;
}

[NOIp 2017]逛公园的更多相关文章

  1. NOIP 2017 逛公园 记忆化搜索 最短路 好题

    题目描述: 策策同学特别喜欢逛公园.公园可以看成一张N个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. ...

  2. NOIP 2017 逛公园 - 动态规划 - 最短路

    题目传送门 传送门 题目大意 给定一个$n$个点$m$条边的带权有向图,问从$1$到$n$的距离不超过最短路长度$K$的路径数. 跑一遍最短路. 一个点拆$K + 1$个点,变成一个DAG上路径计数问 ...

  3. 洛谷 P3953 [ NOIP 2017 ] 逛公园 —— 最短路DP

    题目:https://www.luogu.org/problemnew/show/P3953 主要是看题解...还是觉得好难想啊... dfs DP,剩余容量的损耗是边权减去两点最短路差值...表示对 ...

  4. NOIP 2017 逛公园 题解

    题面 这道题是一道不错的计数类DP: 首先我们一定要跑一遍dijkstra来求得每个点到1号点的最短路: 注意题干,题中并没有说所有点都可以到达n好点,只说了存在一条1号点到n号点的路径:所以我们在反 ...

  5. 【NOIP 2017】逛公园

    Description 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要 ...

  6. [NOIP 2017 day1]逛公园

    题目描述 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要 ...

  7. 逛公园[NOIP2017 D2 T3](dp+spfa)

    题目描述 策策同学特别喜欢逛公园. 公园可以看成一张 \(N\)个点\(M\) 条边构成的有向图,且没有自环和重边.其中 1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值,代表策策经过这条 ...

  8. NOIP2017 Day1 T3 逛公园

    NOIP2017 Day1 T3 更好的阅读体验 题目描述 策策同学特别喜欢逛公园.公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,\(N\)号点 ...

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

    题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...

随机推荐

  1. lda模型的python实现

    LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,最近看了点资料,准备使用python实现一下.至于数学模型相关知识,某度一大堆,这里也给出之前参考过的一个挺详细 ...

  2. VC使用双缓冲制作绘图控件

    最近用VC做了一个画图的控件.控件在使用的时候遇到点问题.在控件里画了图之后切换到其他页面,等再切换回来的时候,发现控件里画的图都不见了.这是因为VC里面,当缩小.遮挡页面后客户区域就会失效,当再次显 ...

  3. 会议室预订系统(meeting room booking system)

    一.mrbs mrbs:(meeting room booking system) 二.效果   三.models from django.db import models # Create your ...

  4. 【WebLogic使用】1.WebLogic的下载与安装

    一.WebLogic的介绍    WebLogic是美国bea公司出品的一个application server,确切的说是一个基于Javaee架构的中间件,纯java开发的,最新版本WebLogic ...

  5. Android添加全屏启动画面

    有的Android软件需要在启动的时候显示一个启动画面,可以是一张图或者一些设置什么呢,还有一个好处就是,可以趁机在后台加载数据.创建启动画面一般有两种方式:1.建立一个activity,展示启动画面 ...

  6. TensorFlow saved_model 模块

    最近在学tensorflow serving 模块,一直对接口不了解,后面看到这个文章就豁然开朗了, 主要的困难在于   tf.saved_model.builder.SavedModelBuilde ...

  7. 应用通信-方案一:RestTemplate

    @RestController public class ClientController { @Autowired private LoadBalancerClient loadBalancerCl ...

  8. hadoop之 map个数控制

    hadooop提供了一个设置map个数的参数mapred.map.tasks,我们可以通过这个参数来控制map的个数.但是通过这种方式设置map的个数,并不是每次都有效的.原因是mapred.map. ...

  9. js页面跳转,url带url参数解决方案

    今天,在做一个项目的时候,向后端发送了一个Ajax请求,后端返回了一个字符串,告诉我未登录.那么我需要跳转到登录页面,同时告诉登录页面,登录成功后,需要跳回的url.也就是标题所说,url中的一个参数 ...

  10. 事务内执行sql修复的简易模板

    -- ============================================= -- Script Template -- ============================= ...