1. 程式人生 > >P3953 逛公園

P3953 逛公園

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 逛公園