Forever Young

「考前日志」11.16

总结

最近状态不对劲

今日已完成

  • 一节文化课:英语完形填空小技巧

    =_=这节课讲的东西还不如我自己的方法

  • AcWing287 积蓄程度
    换根DP,树形DP

    挺基础的换根DP了。随便找一个点作为根,记录每个点的度数,设 \(f_x\) 表示以 \(x\) 为根的子树,把 \(x\) 作为源点,从 \(x\) 出发流向子树的最大流量是多少,用 \(du_x\) 表示 \(x\) 的度数,有转移方程:

    \[f_{x}=\sum\limits_{to\in{Son_{x}}}\begin{cases}\min(f_{to},val(x,to))&\text{if }du_{to}>1\\val(x,to)&\text{if }du_{to}=1\end{cases} \]

    之后考虑换根求出以每个点为根的答案,设 \(g_x\) 表示以 \(x\) 为整棵树的根所能流过的最大流量,因为每个 \(x\) 的儿子 \(to\) 都已经处理完了自身子树内的最大流量 \(f_{to}\),所以只需要处理 \(x\) 除了以 \(to\) 为根的子树之外的部分对 \(g_{to}\) 的贡献,那么有:

    \[g_{to}=f_{to}+\begin{cases}\min(g_{x}-\min({f_{to},val(x,to)}),val(x,to))&\text{if }du_{x}>1\\val(x,to)&\text{if } du_{x}=1\end{cases} \]

    发现是要自顶向下更新的,所以先更新,再进一步遍历。

    调了挺久发现是数组开小了= =

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    const int A = 2e5 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    struct node { int to, nxt, val; } e[A << 1];
    int n, cnt, head[A], f[A], vis[A], g[A], du[A];
    
    inline void add(int from, int to, int val) {
      e[++cnt].to = to;
      e[cnt].val = val;
      e[cnt].nxt = head[from];
      head[from] = cnt;
    }
    
    inline void init() {
      cnt = 0;
      memset(f, 0, sizeof(f));
      memset(g, 0, sizeof(g));
      memset(du, 0, sizeof(du));
      memset(head, 0, sizeof(head));
    }
    
    void dfs(int x, int fa) {
      for (int i = head[x]; i; i = e[i].nxt) {
        int to = e[i].to;
        if (to == fa) continue;
        dfs(to, x);
        if (du[to] == 1) f[x] = f[x] + e[i].val;
        else f[x] = f[x] + min(e[i].val, f[to]);
      }
    }
    
    void change(int x, int fa) {
      for (int i = head[x]; i; i = e[i].nxt) {
        int to = e[i].to;
        if (to == fa) continue;
        if (du[x] == 1) g[to] = f[to] + e[i].val;
        else g[to] = f[to] + min(e[i].val, g[x] - min(f[to], e[i].val));
        change(to, x);
      }
    }
    
    inline void solve() {
      init();
      n = read();
      for (int i = 1; i < n; i++) {
        int x = read(), y = read(), val = read();
        du[x]++, du[y]++;
        add(x, y, val), add(y, x, val);
      }
      dfs(1, 0);
      g[1] = f[1];
      change(1, 0);
      int ans = 0;
      for (int i = 1; i <= n; i++) ans = max(ans, g[i]);
      cout << ans << '\n';
      return;
    }
    
    signed main() {
      int T = read();
      while (T--) solve();
    }
    
  • 洛谷 P2018 消息传递

    树形DP,见此博客

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 1e3 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    struct node { int to, nxt; } e[A << 1];
    int n, ans[A], f[A], head[A], cnt = 0, res = inf; 
    
    inline void add(int from, int to) {
      e[++cnt].to = to;
      e[cnt].nxt = head[from];
      head[from] = cnt;
    }
    
    bool cmp(int x, int y) {
      return x > y;
    }
    
    inline void dfs(int x, int fa) {
      int tot = 0, b[1000] = {0};
      for (int i = head[x]; i; i = e[i].nxt) {
        int to = e[i].to;
        if (to == fa) continue;
        dfs(to, x);
        b[++tot] = f[to];
      }
      sort(b + 1, b + 1 + tot, cmp);
      for (int i = 1; i <= tot; i++) 
        f[x] = max(f[x], b[i] + i);
    }
    
    int main() {
      n = read();
      for (int i = 2; i <= n; i++) {
        int x = read();
        add(x, i), add(i, x);
      }
      for (int i = 1; i <= n; i++) {
        memset(f, 0, sizeof(f));
        dfs(i, 0);
        res = min(f[i], res);
        ans[i] = f[i];
      }
      cout << res + 1 << '\n';
      for (int i = 1; i <= n; i++) 
        if (ans[i] == res) cout << i << " ";
      puts("");
      return 0;
    }
    
  • AcWing288 休息时间

    环形DP问题的转化

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 3831;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    int n, m, a[A], f[2][A][2], ans, now = 0, last = 1;
    
    int main() {
      n = read(), m = read();
      for (int i = 1; i <= n; i++) a[i] = read();
      memset(f, 0xcf, sizeof(f));
      f[now][0][0] = f[now][1][1] = 0;
      for (int i = 2; i <= n; i++) {
        swap(now, last);
        //debug:j从1开始枚举的 
        for (int j = 0; j <= m; j++) {
          f[now][j][0] = max(f[last][j][0], f[last][j][1]);
          if (j) f[now][j][1] = max(f[last][j - 1][0], f[last][j - 1][1] + a[i]);
        }
        memset(f[last], 0xcf, sizeof(f[last]));
      }
      ans = max(f[now][m][0], f[now][m][1]);
      memset(f, 0xcf, sizeof(f));
      f[now][1][1] = a[1], f[now][0][0] = 0;
      //忘记初始化f[now][0][0] 
      for (int i = 2; i <= n; i++) {
        swap(now, last);
        //debug:j从1开始枚举的
        for (int j = 0; j <= m; j++) {
          f[now][j][0] = max(f[last][j][0], f[last][j][1]);
          if (j) f[now][j][1] = max(f[last][j - 1][0], f[last][j - 1][1] + a[i]);
        }
        memset(f[last], 0xcf, sizeof(f[last]));
      }
      ans = max(ans, f[now][m][1]);
      cout << ans << '\n';
      return 0;
    }
    
posted @ 2020-11-16 07:36  Loceaner  阅读(264)  评论(3编辑  收藏  举报