P3953 逛公園
阿新 • • 發佈:2018-10-27
mes 線段樹 存在 net con tdi tail 所有路徑 clas
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\n", dp(k, p, n)); } return 0; }
P3953 逛公園