「考前日志」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; }
转载不必联系作者,但请声明出处