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\n", dp(k, p, n));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/qdscwyy/p/9860546.html

时间: 2024-10-01 09:49:11

P3953 逛公园的相关文章

[Luogu P3953] 逛公园 (最短路+拓扑排序+DP)

题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易可以想到一个做法,就是魔改迪杰斯特拉做法: 如果一个点可以更新到达其他点的距离,那个点的方案数就是这个点的方案数:如果一个点所更新出来的距离和之前的相等,那个点的方案数加等当前点的方案数. 用式子可以表现为: f[j]=f[i] (dis[j]>dis[i]+x)   f[j]+=f[i] (dis

Luogu P3953 逛公园(最短路+记忆化搜索)

P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从 \(1\) 号点进去,从 \(N\) 号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果 \(

Luogu P3953【NOIP2017】逛公园【最短路+拓扑排序+动态规划】

题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从NN号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线. 策策

P3953 NOIP2017 d1t3 逛公园

题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN 个点MM 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从NN 号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到NN 号点的最短路长为dd ,那么策策只会喜欢长度不超过d + Kd+K 

洛谷3953:逛公园——题解

https://www.luogu.org/problemnew/show/P3953 策策同学特别喜欢逛公园.公园可以看成一张n个点m条边构成的有向图,且没有自环和重边.其中1号点是公园的入口,n号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从n号点出来. 策策喜欢新鲜的事物,他不希望有两天逛公园的路线完全一样,同时策策还是一个特别热爱学习的好孩子,他不希望每天在逛公园这件事上花费太多的时间.如果1号点到n号点的最短路长为d

TYVJ1427 小白逛公园

P1427 小白逛公园 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了.    一开始,小白就根据公园的风景给每个公园打了分-.-.小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a.b两个公园)选择连续的一些公园玩.小白当然希望选出的公园的分数总和尽量高咯

线段树--小白逛公园nkoj1316

小白逛公园 Time Limit:20000MS  Memory Limit:65536K Case Time Limit:2000MS Description 小新经常陪小白去公园玩,也就是所谓的遛狗啦-在小新家附近有一条"公园路",路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了. 一开始,小白就根据公园的风景给每个公园打了分-.-.小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a.b两个公园)选择连续的

luogu 3953 逛公园

noip2017 D1T3 逛公园 某zz选手看到数据范围直接就最短路计数了,结果写错了爆零 题目大意: N个点M条边构成的有向图,且没有自环和重边.其中1号点是起点,N号点是公园的终点,每条边有一个非负权值, 代表经过这条边所要花的时间 如果1号点到N号点的最短路长为d,那么策策只选择长度不超过d + K的路线 求总共有多少条满足条件的路线 为避免输出过大,答案对P取模. 如果有无穷多条合法的路线,请输出?1 思路: 首先需要求出最短路用spfa 然后我们dfs的时候dp 具体见注释 1 #i

NOIP2017D1T3逛公园——哎呦!

#include<cstdio> #include<cstring> #define MXN 100001 #define MXM 200001 #define MXK 51 int afst[MXM],anxt[MXM],av[MXM],aw[MXM]; int bfst[MXM],bnxt[MXM],bv[MXM],bw[MXM]; int dis[MXN],queue[10*MXN]; int f[MXN][MXK],vis[MXN][MXK]; int n,m,k,p,t,