2024.12.17 CW 模拟赛
T1
算法
背包, 动态规划.
思路
考虑到 \(w_i \le 1000\), 可以得到状态 \(f_{i,j}\) 表示到第 i 个, 已经有 j 能力的最大精彩度.
然后就是正常 01 背包了.
最后将两序列相同的 j 合并, 最后取最大值即可.
时间复杂度 \(\mathcal{O}(n^3)\). (真的可以过!)
#include "bits/stdc++.h"
using namespace std;
constexpr int N = 1e3 + 1;
#define int long long
int n, m, suma = 0, sumb = 0;
struct Node {
int w, v;
} a[N], b[N];
void init() {
mt19937_64 rnd(time(0));
cin >> n >> m;
for (int i = 1; i <= n; ++i)
cin >> a[i].w >> a[i].v, suma += a[i].w;
shuffle(a + 1, a + n + 1, rnd);
for (int i = 1; i <= m; ++i)
cin >> b[i].w >> b[i].v, sumb += b[i].w;
shuffle(b + 1, b + m + 1 , rnd);
}
int f[N * N], g[N * N];
void calculate() {
memset(f, 128, sizeof f);
memset(g, 128, sizeof g);
f[0] = g[0] = 0;
for (int i = 1; i <= n; ++i)
for (int j = suma; j >= a[i].w; --j)
f[j] = max(f[j], f[j - a[i].w] + a[i].v);
for (int i = 1; i <= m; ++i)
for (int j = sumb; j >= b[i].w; --j)
g[j] = max(g[j], g[j - b[i].w] + b[i].v);
int ans = -1e18;
for (int i = min(suma, sumb); i; --i)
if (f[i] >= -1e9 and g[i] >= -1e9)
ans = max(ans, f[i] + g[i]);
if (ans < 0)
ans = 0;
cout << ans << '\n';
}
void solve() {
init();
calculate();
}
signed main() {
cin.tie(nullptr)->sync_with_stdio(false);
solve();
return 0;
}
T2
算法
组合数学.
思路
对每一条边进行考虑.
假定 1 号点为根, 每个点的子树大小为 \(x\).
对于某一条边, \(m\) 个点一定分布在它的左右两端, 因为要使得代价最小,
所以一定是点数小的一边向点数大的一边走, 那么这条边就会被经过 \(\min(m-i,\ i)\) 次.
于是, 对于每一条边都有以下式子:
\[f(x) = \sum_{i = 1}^m \min(i,\ m - i) \cdot \tbinom{x}{i} \cdot \tbinom{n - x}{m - i}
\]
最后答案即 \(\sum f(\)子树大小\()\).
这个 \(\min\) 比较麻烦, 拆开一下:
\[f(x) = \sum_{i = 1}^{\frac{m - 1}{2}} i \cdot \tbinom{x}{i} \cdot \tbinom{n - x}{m - i} + \sum_{i = \frac{m - 1}{2} + 1}^{m} (m - i) \cdot \tbinom{x}{i} \cdot \tbinom{n - x}{m - i}
\]
令 \(t = \frac{m - 1}{2}\).
先处理左半部分:
\[g(x) = \sum^t_{i = 1} i \cdot \tbinom{x}{i} \cdot \tbinom{n - x}{m - i} = \sum^t_{i = 1} x \cdot \tbinom{x - 1}{i - 1} \cdot \tbinom{n - x}{m - i}
\]
\[\leftrightarrow \frac{g(x)}{x} = \sum^t_{i = 1} \tbinom{x - 1}{i - 1} \cdot \tbinom{n - x}{m - i}
\]
这样就可以 \(\mathcal{O}(n)\) 递推 \(s(x)\), 进而处理 \(g(x)\) 了.
#include "iostream"
using namespace std;
constexpr int N = 2e6 + 10, mod = 1e9 + 7;
int n, m;
int inv[N], fac[N];
int sz[N], fa[N];
void init() {
cin >> n >> m;
sz[1] = 1;
for (int v = 2; v <= n; ++v)
cin >> fa[v], sz[v] = 1;
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for (int i = 2; i <= 1e6; ++i) {
fac[i] = 1ll * fac[i - 1] * i % mod;
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
}
for (int i = 2; i <= 1e6; ++i)
inv[i] = 1ll * inv[i] * inv[i - 1] % mod;
}
#define get(x, y) (1ll * fac[(y)] * (1ll * inv[(y) - (x)] * inv[(x)] % mod) % mod)
int f[N];
void calculate() {
int t = m - 1 >> 1, ans = 0;
f[1] = (!t ? 0 : get(m - 1, n - 1));
for (int i = 2; i ^ n; ++i)
f[i] = (mod + f[i - 1] - get(t - 1, i - 2) * get(m - t - 1, n - i) % mod) % mod;
for (int i = 1; i ^ n; ++i)
f[i] = 1ll * f[i] * i % mod;
for (int i = 1; i <= n - i; ++i) {
f[i] = f[n - i] = (f[i] + f[n - i]) % mod;
if (!(m & 1))
f[i] = f[n - i] = (f[i] + 1ll * get(t + 1, i) * get(t + 1, n - i) % mod * (t + 1) % mod) % mod;
}
for (int i = n; i ^ 1; --i) {
sz[fa[i]] += sz[i];
ans = (ans + f[sz[i]]) % mod;
}
cout << ans << '\n';
}
void solve() {
init();
calculate();
}
int main() {
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现