P3953 逛公园
Posted qdscwyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3953 逛公园相关的知识,希望对你有一定的参考价值。
Description
策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从N号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对PP取模。
如果有无穷多条合法的路线,请输出-1。
Solution
参考了题解 P3953 【逛公园】可能是长沙一位大佬的题解.
没有零环
首先考虑没有零环的情况, 这时候只需要用一个类似于最短路计数的做法.
首先求出 1 号点到所有点的最短路.
用(f(u,j))表示从一到(u)的所有路径中小于(dis_u+j)的有多少条.
(f(u,j))可以转移到(f(v,dis_u + c + j - dis_v))
如果存在边((u, v))且边权为(c)的话.
这样的话需要先更新(dis)小的点.
对了, 注意转移的枚举顺序, 先枚举(j), 再枚举$$
优化
需要优化的呀!
因为会超时的呀!
所以我就优化了一上午
- 内存池开好
- 手写
pair<int, int>
- zkw线段树优化dijkstra
- 读入优化
ZKW线段树参考了这里
Code
#include <math.h>
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const int inf = 0x3f3f3f3f;
const int N = 100003;
using namespace std;
namespace {
struct Node {
int v; int id;
Node() { }
Node(int _value): v(_value) {}
Node(int _, int __) : v(_), id(__) {}
bool operator < (const Node& o) const {
return v < o.v;
}
};
class Heap {
private:
Node *d; int n;
public:
Heap(int _MaxN) {
n = 1 << (1 + (int) (log(_MaxN) / log(2.0)));
d = new Node[n << 1];
for (int i = 1; i <= n + n - 1; i++)
d[i] = Node(inf, i - n + 1);
}
~Heap() { }
inline int top_pos() {
return d[1].id;
}
inline void modify(int pos, int s) {
int p = pos + n - 1;
d[p].v = s;
while (p) {
p >>= 1,
d[p] = min(d[(p << 1) + 1], d[p << 1]);
}
}
};
}
struct Edge {
int v, c; Edge* nxt;
Edge() : nxt(nullptr) {}
Edge(int pos, int __, Edge* ___) : v(pos), c(__), nxt(___) {}
} *head[N], pool[1000005];
int cnt;
#define new_Edge(u, v, c) (pool[cnt] = Edge(u, v, c), &pool[cnt++])
#define AddEdge(u, v, c) head[u] = new_Edge(v, c, head[u])
int dis[N];
const int MAXIN = 1 << 22;
char IN[MAXIN], *SS = IN, *TT = IN;
#define gc() (SS == TT && (TT = (SS = IN) + fread(IN, 1, MAXIN, stdin), SS == TT) ? EOF : *SS++)
inline int read() {
int now = 0; register char c = gc();
for (; !isdigit(c); c = gc());
for (; isdigit(c); now = now * 10 + c - '0', c = gc());
return now;
}
struct Pair {
int dis, id;
Pair() {}
Pair(int pos, int __) : dis(pos), id(__) {}
bool operator < (const Pair& o) const {
return dis > o.dis;
}
};
void dijkstra(int n) {
Heap* T = new Heap(n + 1);
memset(dis, 0x3f, sizeof dis);
dis[1] = 0, T->modify(1, 0);
for (int i = 1; i <= n; i += 1) {
int u = T->top_pos();
T->modify(u, inf);
for (auto edge = head[u]; edge; edge = edge->nxt) {
int v = edge->v;
if (dis[v] > dis[u] + edge->c)
dis[v] = dis[u] + edge->c,
T->modify(v, dis[u] + edge->c);
}
}
}
int f[N][51];
Pair F[N];
int dp(int k, const int mod, int n) {
for (int i = 1; i <= n; i += 1)
F[i] = Pair(-dis[i], i);
memset(f, false, sizeof f);
sort(F + 1, F + n + 1);
f[1][0] = 1;
for (int j = 0; j <= k; j += 1) {
for (int i = 1; i <= n; i += 1) {
int u = F[i].id;
if (not f[u][j]) continue;
for (auto edge = head[u]; edge; edge = edge->nxt) {
int v = edge->v, ly = dis[u] + j + edge->c - dis[v];
if (ly <= k) f[v][ly] = (f[v][ly] + f[u][j]) % mod;
}
}
}
int res = 0;
for (int i = 0; i <= k; i += 1)
res = (res + f[n][i]) % mod;
return res;
}
int main () {
int T = read();
while (T--) {
int n, m, k, p;
n = read(), m = read(), k = read(), p = read();
for (int i = 1; i <= n; i += 1) head[i] = nullptr;
for (int i = 0, u, v, c; i < m; i += 1) {
u = read(), v = read(), c = read();
AddEdge(u, v, c);
}
dijkstra(n);
printf("%d
", dp(k, p, n));
}
return 0;
}
以上是关于P3953 逛公园的主要内容,如果未能解决你的问题,请参考以下文章
[luogu P3953] [noip2017 d1t3] 逛公园