abc 390 题解
ABC 略
D
首先将 \(N\) 个不同的数分成若干非空组的方案数是贝尔数 \(B(N)\),且 \(B(12) < 5 \times 10^6\),所以我们可以暴力求出所有的组合方案来求解。
CODE
std::unordered_set<i64> vis;
i64 val;
void dfs(int cur, int bags) {
// 枚举装到第几号袋子里面
for (int i = 0; i <= bags; i++) {
val ^= sum[i];
sum[i] += a[cur];
val ^= sum[i];
if (cur == n - 1) {
vis.insert(val);
} else {
dfs(cur + 1, bags + (i == bags));
}
val ^= sum[i];
sum[i] -= a[cur];
val ^= sum[i];
}
return;
}
E
由于每种食物只包含一种维生素,所以对每种维生素单独求出 \(dp[j]\),表示 \(j\) 单位卡路里最多能有的这种维生素的含量。
之后我们贪心地求最大的最小值,具体的:一开始我们每种维生素都分配 0 单位卡路里,我们一单位一单位地分配卡路里,每次分配给现在含量最少的那个维生素。若有相同的就任意选择一个。
CODE
void solve()
{
int n = 0, x = 0;
std::cin >> n >> x;
std::vector val(3, std::vector<std::pair<int, int>>{});
for (int i = 0; i < n; ++i)
{
int a = 0, b = 0, c = 0;
std::cin >> a >> b >> c;
val[a - 1].emplace_back(b, c);
}
auto work = [&](std::vector<std::pair<int, int>> &v) -> std::vector<int> {
std::vector dp(x + 1, 0); // dp[i] 表示花费 i 的最大价值
for (int i = 0; i < v.size(); ++i)
{
for (int j = x; j >= v[i].second; --j)
{
dp[j] = std::max(dp[j], dp[j - v[i].second] + v[i].first);
}
}
return dp;
};
std::vector dp = { work(val[0]), work(val[1]), work(val[2]) };
std::array<int, 3> id{0, 0, 0};
for (int i = 0; i < x; ++i)
{
int mn = std::min({ dp[0][id[0]], dp[1][id[1]], dp[2][id[2]] });
for (int j = 0; j < 3; ++j)
{
if (dp[j][id[j]] == mn)
{
++id[j];
break;
}
}
}
std::cout << std::min({ dp[0][id[0]], dp[1][id[1]], dp[2][id[2]] }) << '\n';
}
F
假设我已经知道了\(f[L, R]\),接下来要求 \(f[L, R + 1]\),且 \(a[R + 1] = x\),则有以下几种情况
- 若原序列在 \([L, R]\) 这个区间中不存在 \(\{ x - 1, x, x + 1 \}\) 中的任何数,则 \(f[L, R + 1] = f[L, R]\) + 1。
- 若原序列在 \([L, R]\) 这个区间中存在 \(\{ x - 1, x, x + 1 \}\) 中的任意非空非 \(\{ x + 1, x - 1 \}\) 的子集,则 \(f[L, R + 1] = f[L, R]\)。
- 若原序列在 \([L, R]\) 这个区间中不存在 \(x\),且存在 \(x - 1\) 和 \(x + 1\),则 \(f[L, R + 1] = f[L, R] - 1\)。
能否基于以上转移求解从 \(\sum_{i = L}^{R}f(i, R)\) 到 \(\sum_{i = L}^{R + 1}f(i, R + 1)\) 的转移?答案是可行的,但还需要一点观察,就是 \(f(i, R + 1) - f(i, R)\) 在 \(i \in [L, R + 1]\) 是不降的,且值域是 \(\{ -1, 0, 1 \}\),转移的关键就是根据上面所说的几种情况,找到 \(f(i, R + 1) - f(i, R)\) 的分界点。
于是 \(R\) 从 \(1\) 到 \(N\)依次求得 \(\sum_{i = 1}^{R}f(i, R)\),然后答案就是 \(\sum_{R = 1}^{N}\sum_{i = 1}^{R}f(i, R)\)
总的时间复杂度是 \(O(n)\)
CODE
void solve()
{
int n = 0;
std::cin >> n;
std::vector<int> a(n);
for (auto &i : a) {
std::cin >> i;
}
std::vector<int> p(n + 2, -1);
std::vector<i64> f(n, 0ll);
f[0] = 1;
for (int i = 0; i + 1 < n; i++) {
p[a[i]] = i;
int cur = a[i + 1];
f[i + 1] = 1 + f[i]; // 这里的 1 是 { a[i + 1] }
// 要 +1 的区间的数量
f[i + 1] += (i - std::max( {p[cur - 1], p[cur], p[cur + 1] }));
if (p[cur] < p[cur + 1] && p[cur] < p[cur - 1]) {
// 要 -1 的区间的数量
f[i + 1] -= std::min( {p[cur - 1], p[cur + 1]}) - p[cur];
}
}
std::cout << std::accumulate(f.begin(), f.end(), 0ll) << '\n';
return;
}
浙公网安备 33010602011771号