标签:dad msu 测试 gre efi har table sample list
策策同学特别喜欢逛公园。公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从NN号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对PP取模。
如果有无穷多条合法的路线,请输出−1。
第一行包含一个整数 T, 代表数据组数。
接下来TT组数据,对于每组数据: 第一行包含四个整数 N,M,K,PN,M,K,P,每两个整数之间用一个空格隔开。
接下来MM行,每行三个整数a_i,b_i,c_iai?,bi?,ci?,代表编号为a_i,b_iai?,bi?的点之间有一条权值为 c_ici?的有向边,每两个整数之间用一个空格隔开。
输出文件包含T 行,每行一个整数代表答案。
【样例解释1】
对于第一组数据,最短路为 3。 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 为 3 条合法路径。
【测试数据与约定】
对于不同的测试点,我们约定各种参数的规模不会超过如下
| 测试点编号 | TT | NN | MM | KK | 是否有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 <= P <= 10^9,1 <= a_i,b_i <= N ,0 <= c_i <= 1000, 1≤P≤109,1≤ai?,bi?≤N , 0≤ci?≤1000。
数据保证:至少存在一条合法的路线。
首先从起点和终点的最短路一定是要跑的。
注意到k不大于50, nk的动态规划是可以考虑的。
设起点到第i个点最短路为dis[i] , 这样dp[i][j]表示到第i个点长度为dis[i]+j的路径条数。
考虑到可以同一层转移,显然这种转移边满足dis[x] + len == dis[y]。
那么我么拓扑排序一下确定转移顺序即可。
考虑-1的情况,若有零环且存在通过零环并且长度<=dis[n]+k的路径则答案无限大。
namespace可好写了,写得可长了。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define travel(x, i) for (int i = fir[x]; i; i = e[i].nxt)
using namespace std;
namespace fastIO {
#define buf_size 1000000
bool error;
inline char gc() {
static char buf[buf_size + 1], *l = buf, *r = buf;
if (l == r) {
l = buf;
r = buf + fread(buf, 1, buf_size, stdin);
if (l == r) {error = 1; return -1;}
}
return *l ++;
}
inline bool isnum(char ch) {
return (‘0‘ <= ch && ch <= ‘9‘) || ch == ‘-‘;
}
inline void read(int &x) {
char ch; x = 0;
while (!isnum(ch = gc()) && !error);
if (error) return;
do {x = (x << 1) + (x << 3) + ch - ‘0‘;} while (isdigit(ch = gc()) && !error);
}
#undef buf_size
}
using namespace fastIO;
typedef pair <int, int> pii;
const int N = 1e5 + 5;
const int M = 2e5 + 5;
int n, m, k, mod;
int ans[N][52];
namespace Graph1 {
struct edge {
int nxt, to, len;
} e[M];
int fir[N], dis[N], cnt;
bool in[N];
inline void clear() {memset(fir, 0, sizeof fir); cnt = 0;}
inline void add(int x, int y, int l) {
e[++ cnt] = (edge){fir[x], y, l};
fir[x] = cnt;
}
inline void dijkstra() {
memset(dis, -1, sizeof dis);
memset(in, 0, sizeof in);
priority_queue <pii, vector <pii>, greater <pii> > Q;
Q.push(make_pair(0, 1));
dis[1] = 0;
pii cur;
int x;
while (!Q.empty()) {
cur = Q.top(); Q.pop();
x = cur.second;
if (in[x]) continue;
in[x] = 1;
travel(x, i)
if (!in[e[i].to] && (dis[x] + e[i].len < dis[e[i].to] || dis[e[i].to] == -1)) {
dis[e[i].to] = dis[x] + e[i].len;
Q.push(make_pair(dis[e[i].to], e[i].to));
}
}
}
}
namespace Graph2 {
struct edge {
int nxt, to, len;
} e[M];
int fir[N], dis[N], cnt;
bool in[N];
inline void clear() {memset(fir, 0, sizeof fir); cnt = 0;}
inline void add(int x, int y, int l) {
e[++ cnt] = (edge){fir[x], y, l};
fir[x] = cnt;
}
inline void dijkstra() {
memset(dis, -1, sizeof dis);
memset(in, 0, sizeof in);
priority_queue <pii, vector <pii>, greater <pii> > Q;
Q.push(make_pair(0, n));
dis[n] = 0;
pii cur;
int x;
while (!Q.empty()) {
cur = Q.top(); Q.pop();
x = cur.second;
if (in[x]) continue;
in[x] = 1;
travel(x, i)
if (!in[e[i].to] && (dis[x] + e[i].len < dis[e[i].to] || dis[e[i].to] == -1)) {
dis[e[i].to] = dis[x] + e[i].len;
Q.push(make_pair(dis[e[i].to], e[i].to));
}
}
}
}
namespace Graph3 {
struct edge {
int nxt, to;
} e[M];
int fir[N], cnt = 0, tot;
int ord[N], deg[N];
inline void clear() {
memset(fir, 0, sizeof fir);
memset(deg, 0, sizeof deg);
cnt = 0;
}
inline void add(int x, int y) {
e[++ cnt] = (edge){fir[x], y};
fir[x] = cnt;
deg[y] ++;
}
inline void topo() {
queue <int> Q;
for (int i = 1; i <= n; i ++)
if (!deg[i]) Q.push(i);
int x; tot = 0;
while (!Q.empty()) {
x = Q.front(); Q.pop();
ord[++ tot] = x;
travel(x, i) {
deg[e[i].to] --;
if (!deg[e[i].to]) Q.push(e[i].to);
}
}
}
}
namespace Graph4 {
struct edge {
int nxt, to;
} e[M];
int fir[N], deg[N], cnt;
inline void clear() {
memset(fir, 0, sizeof fir);
memset(deg, 0, sizeof deg);
cnt = 0;
}
inline void add(int x, int y) {
e[++ cnt] = (edge){fir[x], y};
fir[x] = cnt;
deg[y] ++;
}
inline bool topo() {
queue <int> Q;
for (int i = 1; i <= n; i ++)
if (!deg[i]) Q.push(i);
int x;
while (!Q.empty()) {
x = Q.front(); Q.pop();
travel(x, i) {
deg[e[i].to] --;
if (!deg[e[i].to]) Q.push(e[i].to);
}
}
for (int i = 1; i <= n; i ++)
if (deg[i] && Graph1 :: dis[i] + Graph2 :: dis[i] <= Graph1 :: dis[n] + k) return 0;
return 1;
}
}
int x[M], y[M], l[M];
inline void modadd(int &x, int y) {
if ((x += y) >= mod) x -= mod;
}
using namespace Graph1;
inline void solve(int T) {
clear();
Graph2 :: clear();
Graph3 :: clear();
Graph4 :: clear();
read(n); read(m); read(k); read(mod);
for (int i = 1; i <= m; i ++) {
read(x[i]); read(y[i]); read(l[i]);
add(x[i], y[i], l[i]);
Graph2 :: add(y[i], x[i], l[i]);
}
dijkstra();
Graph2 :: dijkstra();
for (int i = 1; i <= m; i ++) {
if (dis[x[i]] == -1 || Graph2 :: dis[y[i]] == -1) continue;
if (dis[x[i]] + l[i] == dis[y[i]]) Graph3 :: add(x[i], y[i]);
if (l[i] == 0) Graph4 :: add(x[i], y[i]);
}
if (Graph4 :: topo() == 0) return (void)puts("-1");
Graph3 :: topo();
memset(ans, 0, sizeof ans);
ans[1][0] = 1;
int w, xx, g = Graph3 :: tot;
for (int i = 0; i <= k; i ++) {
for (int j = 1; j <= g; j ++) {
xx = Graph3 :: ord[j];
if (dis[xx] == -1) continue;
travel(xx, p) {
w = dis[xx] + i + e[p].len - dis[e[p].to];
if (0 <= w && w <= k) modadd(ans[e[p].to][w], ans[xx][i]);
}
}
}
int Ans = 0;
for (int i = 0; i <= k; i ++) modadd(Ans, ans[n][i]);
printf("%d\n", Ans);
}
int main() {
int T;
read(T);
while (T --) solve(T);
return 0;
}
Luogu P3953【NOIP2017】逛公园【最短路+拓扑排序+动态规划】
标签:dad msu 测试 gre efi har table sample list
原文地址:http://www.cnblogs.com/the-unbeatable/p/7894494.html