• NOIP 2017 逛公园


    题目传送门

      传送门

    题目大意

      给定一个$n$个点$m$条边的带权有向图,问从$1$到$n$的距离不超过最短路长度$K$的路径数。

      跑一遍最短路。

      一个点拆$K + 1$个点,变成一个DAG上路径计数问题。直接拓扑排序加动态规划,如果有一个$n$号点的剩余度数非0,就一个合法的路径上存在零环(这样可以无线走了)。

      于是成功T掉了。

      把拓扑排序变成不建图,从$n$开始记忆化搜索,然后就过了。

      我居然把模数P打错成M调了一个上午,果然我菜啊。。。

      下面这份代码获得了 97 分的好成绩,我也不知道发生了什么。

    Code

      1 /**
      2  * Uoj
      3  * Problem#331
      4  * Accepted
      5  * Time: 2392ms
      6  * Memory: 28196k
      7  */
      8 #include <iostream>
      9 #include <cassert>
     10 #include <cstdlib>
     11 #include <cstdio>
     12 #include <vector>
     13 #include <queue>
     14 using namespace std;
     15 typedef bool boolean;
     16 
     17 typedef pair<int, int> pii;
     18 
     19 const int N = 1e5 + 5, M = 2e5 + 5, Kmx = 52;
     20 
     21 const signed int inf = (signed) (~0u >> 1);
     22 
     23 template <typename T>
     24 void pfill(T* pst, const T* ped, T val) {
     25     for ( ; pst != ped; *(pst++) = val);
     26 }
     27 
     28 typedef class Edge {
     29     public:
     30         int ed, nx, w;
     31 
     32         Edge(int ed = 0, int nx = 0, int w = 0):ed(ed), nx(nx), w(w) {    }
     33 }Edge;
     34 
     35 typedef class MapManager {
     36     public:
     37         int *h;
     38         vector<Edge> es;
     39 
     40         MapManager(int n) {
     41             h = new int[(n + 1)];
     42         }
     43 
     44         void init(int n) {
     45             pfill(h + 1, h + n + 1, -1);
     46             es.clear();
     47         }    
     48 
     49         void addEdge(int u, int v, int w) {
     50             es.push_back(Edge(v, h[u], w));
     51             h[u] = (signed) es.size() - 1;        
     52         }
     53 
     54         Edge& operator [] (int p) {
     55             return es[p];
     56         }
     57 }MapManager;
     58 
     59 typedef class Node {
     60     public:
     61         int p, dis;
     62 
     63         Node(int p = 0, int dis = 0):p(p), dis(dis) {    }
     64 
     65         boolean operator < (Node b) const {
     66             return dis > b.dis;
     67         }
     68 }Node;
     69 
     70 int n, m, K, P;
     71 MapManager g(N), _g(N);
     72 
     73 int add(int a, int b) {
     74     return ((a += b) >= P) ? (a - P) : (a);
     75 }
     76 
     77 inline void init() {
     78     scanf("%d%d%d%d", &n, &m, &K, &P);
     79     g.init(n + 1), _g.init(n + 1);
     80     for (int i = 1, u, v, w; i <= m; i++) {
     81         scanf("%d%d%d", &u, &v, &w);
     82         g.addEdge(u, v, w);
     83         _g.addEdge(v, u, w);
     84     }
     85 }
     86 
     87 int f[N];
     88 priority_queue<Node> que;
     89 
     90 int& operator * (Node p) {
     91     return f[p.p];
     92 }
     93 
     94 void dijstra() {
     95     pfill(f + 1, f + n + 1, inf);
     96     que.push(Node(1, f[1] = 0));
     97     while (!que.empty()) {
     98         Node e = que.top();
     99         que.pop();
    100         if (*e != e.dis)
    101             continue;
    102         for (int i = g.h[e.p]; ~i; i = g[i].nx)
    103             if (*e + g[i].w < f[g[i].ed])
    104                 que.push(Node(g[i].ed, f[g[i].ed] = *e + g[i].w));
    105     }
    106 }
    107 
    108 int h[N][Kmx];
    109 unsigned char vis[N][Kmx];
    110 boolean cir = false;
    111 int dp(int p, int dif) {
    112     if (dif > K)
    113         return 0;
    114     if (dif < 0)
    115         return 0;
    116     assert(dif >= 0);
    117     if (vis[p][dif] & 2)
    118         return cir = true;
    119     if (vis[p][dif] & 1)
    120         return h[p][dif];
    121     vis[p][dif] |= 3, h[p][dif] = (p == 1 && dif == 0);
    122     for (int i = _g.h[p], e, nd; ~i; i = _g[i].nx) {
    123         e = _g[i].ed;
    124         if (f[e] == inf)
    125             continue;
    126         nd = f[p] + dif - _g[i].w - f[e];
    127         h[p][dif] = add(h[p][dif], dp(e, nd));
    128         if (cir)
    129             return 0;
    130     }
    131     vis[p][dif] ^= 2;
    132     return h[p][dif];
    133 }
    134 
    135 inline void solve() {
    136     dijstra();
    137     if (f[n] == inf) {
    138         puts("0");
    139         return;
    140     }
    141     cir = false;
    142     pfill(vis[1], vis[n + 1], (unsigned char)0);
    143     int rt = dp(n, 0);
    144     for (int i = 1; i <= K && !cir; i++)
    145         rt = add(rt, dp(n, i));
    146     printf("%d
    ", (cir) ? (-1) : (rt));
    147 }
    148 
    149 int T;
    150 int main() {
    151     scanf("%d", &T);
    152     while (T--) {
    153         init();
    154         solve();
    155     }
    156     return 0;
    157 }
  • 相关阅读:
    python中unicode、utf8、gbk等编码问题
    git常用操作
    python List&Set&Dict交集、并集、差集
    VIM的高级使用
    Logger级别和输出的地方
    Eclipse+pydev 常用快捷键
    架构相关领域的学习材料(转)
    深入浅出之正则表达式(一)
    深入浅出之正则表达式(二)
    软件project总结
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9908553.html
Copyright © 2020-2023  润新知