• bzoj 5290 [HNOI2018] 道路


    bzoj 5290 [HNOI2018] 道路

    Solution

    实际上是个大水题,但是一脸难题的样子

    发现限制了深度小于等于 (40)

    设计状态 (f[i][x][y]) 表示当前点为 (i),当前点到根的路径上有 (x) 条公路没有被翻修,(y) 条铁路没有被翻修

    那么对于所有的叶子节点,就是所有的乡村,可以直接枚举 (x, y) 求出所有 (f) 的值,也就是 ( ext{dp}) 的初值

    然后转移就是枚举当前点连出去的两条边翻修了哪一条,(f[i][x][y] = min(f[ls][x][y]+ f[rs][x][y+1],f[ls][x+1][y]+f[rs][x][y]))

    Code

    // Copyright lzt
    #include<stdio.h>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<string>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef std::pair<int, int> pii;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef std::pair<long long, long long> pll;
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define rep(i, j, k)  for (register int i = (int)(j); i <= (int)(k); i++)
    #define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
    #define Debug(...) fprintf(stderr, __VA_ARGS__)
     
    inline ll read() {
      ll x = 0, f = 1;
      char ch = getchar();
      while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
      }
      while (ch <= '9' && ch >= '0') {
        x = 10 * x + ch - '0';
        ch = getchar();
      }
      return x * f;
    }
     
    const int maxn = 20020;
    int n;
    int ls[maxn], rs[maxn];
    int a[maxn << 1], b[maxn << 1], c[maxn << 1];
    int num[maxn << 1][2];
    ll f[maxn][44][44];
     
    void dfs(int u) {
      if (u >= n) return;
      num[ls[u]][0] = num[u][0] + 1;
      num[ls[u]][1] = num[u][1];
      num[rs[u]][0] = num[u][0];
      num[rs[u]][1] = num[u][1] + 1;
      dfs(ls[u]); dfs(rs[u]);
    }
     
    inline ll calc(int i, int x, int y) {
      if (i < n) return f[i][x][y];
      else return c[i] * 1ll * (a[i] + x) * (b[i] + y);
    }
     
    void work() {
      n = read();
      rep(i, 1, n - 1) {
        ls[i] = read(), rs[i] = read();
        if (ls[i] < 0) ls[i] = -ls[i] + (n - 1);
        if (rs[i] < 0) rs[i] = -rs[i] + (n - 1);
      }
      rep(i, n, n + n - 1) a[i] = read(), b[i] = read(), c[i] = read();
      dfs(1);
      rrep(i, n - 1, 1) {
        rep(x, 0, num[i][0]) rep(y, 0, num[i][1]) {
          f[i][x][y] = min(calc(ls[i], x, y) + calc(rs[i], x, y + 1),
            calc(ls[i], x + 1, y) + calc(rs[i], x, y));
        }
      }
      printf("%lld
    ", f[1][0][0]);
    }
     
    int main() {
      #ifdef LZT
        freopen("in", "r", stdin);
      #endif
     
      work();
     
      #ifdef LZT
        Debug("My Time: %.3lfms
    ", (double)clock() / CLOCKS_PER_SEC);
      #endif
    }
    

    Review

    状态比较特别

    一般的状态都是转移方向为 (y) 转移到 (x) 的时候,(x) 对应的状态包含了 (y) 对应的状态,这道题是反过来的,儿子状态包含了父亲状态,所以可能比较难想清楚

    看到深度 (40),点数 (20000),应该就想到状态了吧。。。

  • 相关阅读:
    asp.net将word转成HTML
    asp.net 控件位置form验证
    javascript 正则表达式
    .net framework处理xml
    XMLHTTP与XMLDOC使用介绍(上)
    一个女程序员的征婚信息的select语句
    解决连接MySql4.0数据库出现的"character_set_results"问题
    javascript与cs代码互访
    杜绝<script src="js/tool.js" type="text/javascript"/>这样写的习惯
    总结:常用的正则表达式集合
  • 原文地址:https://www.cnblogs.com/wawawa8/p/10162805.html
Copyright © 2020-2023  润新知