[NOIp 2017]逛公园
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]逛公园的更多相关文章
- NOIP 2017 逛公园 记忆化搜索 最短路 好题
题目描述: 策策同学特别喜欢逛公园.公园可以看成一张N个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. ...
- NOIP 2017 逛公园 - 动态规划 - 最短路
题目传送门 传送门 题目大意 给定一个$n$个点$m$条边的带权有向图,问从$1$到$n$的距离不超过最短路长度$K$的路径数. 跑一遍最短路. 一个点拆$K + 1$个点,变成一个DAG上路径计数问 ...
- 洛谷 P3953 [ NOIP 2017 ] 逛公园 —— 最短路DP
题目:https://www.luogu.org/problemnew/show/P3953 主要是看题解...还是觉得好难想啊... dfs DP,剩余容量的损耗是边权减去两点最短路差值...表示对 ...
- NOIP 2017 逛公园 题解
题面 这道题是一道不错的计数类DP: 首先我们一定要跑一遍dijkstra来求得每个点到1号点的最短路: 注意题干,题中并没有说所有点都可以到达n好点,只说了存在一条1号点到n号点的路径:所以我们在反 ...
- 【NOIP 2017】逛公园
Description 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要 ...
- [NOIP 2017 day1]逛公园
题目描述 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要 ...
- 逛公园[NOIP2017 D2 T3](dp+spfa)
题目描述 策策同学特别喜欢逛公园. 公园可以看成一张 \(N\)个点\(M\) 条边构成的有向图,且没有自环和重边.其中 1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值,代表策策经过这条 ...
- NOIP2017 Day1 T3 逛公园
NOIP2017 Day1 T3 更好的阅读体验 题目描述 策策同学特别喜欢逛公园.公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,\(N\)号点 ...
- [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)
题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...
随机推荐
- JavaWeb学习笔记七 事务
什么是事务?一件事情有n个组成单元 ,要么这n个组成单元同时成功,要么n个单元就同时失败.就是将n个组成单元放到一个事务中. mysql的事务 默认的事务:一条sql语句就是一个事务,默认就开启事务并 ...
- Beta冲刺合集
Beta冲刺序列: Beta凡事预则立 :Beta No.0 Beta冲刺Day1:Beta No.1 Beta冲刺Day2:Beta No.2 Beta冲刺Day3:Beta No.3 Beta冲刺 ...
- C语言的第一次作业总结
PTA实验作业 题目一:温度转换 本题要求编写程序,计算华氏温度150°F对应的摄氏温度.计算公式:C=5×(F−32)/9,式中:C表示摄氏温度,F表示华氏温度,输出数据要求为整型. 1.实验代码: ...
- 作业01-Java基本概念
1.本周学习总结 本周学习了JVM,JDK,JRE三者之间的区别及联系,知道JDK包括JRE,JRE包括JVM,知道java语言与C语言的不同之处在于java语言可以依赖于虚拟机实现"编译一 ...
- 开发者的如何优雅的使用OSX
Mac对于IT开发者来说是最好的开发工具,没有之一. 但是对于大部分人来说,第一个接触的PC操作系统都是Windows系统,此文将带大家优雅的快速学习和使用Mac的OSX系统. 1. 从键盘说起 Ma ...
- JAVA_SE基础——46.引用数据类型变量.值交换[独家深入解析]
需求:定义一个函数交换数组中两个元素的位置. code 1: import java.util.*; class Demo3 { public static void main(String[] ar ...
- centos7.4下离线安装CDH5.7
(一)安装前的规划 (1)操作系统版本:centos7.4(64bit) [root@hadoop22 etc]# more /etc/centos-release CentOS Linux rele ...
- Mego(08) - 高级建模
对于模型建立Mego还提供了一些高级主题 数据库函数映射 我们可以将现有的CLR方法映射到指定数据库的标题函数上,如下所示 public class OrderManageEntities : DbC ...
- angular路由守卫
路由守卫是指当用户满足了某些要求之后才可以离开或者进入某个页面或者场景的时候使用.比如说只有当用户填写了用户名和密码之后才可以进入首页,比如说用户离开某个页面时明月保存信息提示用户是否保存信息后再离 ...
- 使用pie.htc时Border-radius的兼容
如果一个图层中(navin)使用了pie.htc来对ie6,7,8进行兼容,如若上一层(navwrap)的样式中有背景的属性,则此层 (navin) 在ie6,7,8中背景颜色不显示.如下图:此部分的 ...