1 条题解
-
0
题目分析
我们需要计算区间 内所有数字在 进制表示下,将各位数字代表的石子堆合并成一堆的最小代价。每次移动石子的代价是移动的石子数乘以移动的距离。
解题思路
对于每个数字的 进制表示,我们需要找到最优的合并位置,使得总移动代价最小。通过数位动态规划结合容斥原理,我们可以高效地计算区间内所有数字的最小代价之和。
算法核心
- 数位DP:将数字分解为 进制数位进行处理
- 容斥原理:通过计算所有可能合并位置的代价,利用容斥求出真正的最小代价
- 记忆化搜索:优化状态转移,避免重复计算
完整代码
#include <bits/stdc++.h> using i64 = long long; i64 l, r, k, ans, dp[105][10005]; int tot, a[105]; i64 dfs(int u, i64 nw, int id, bool fg) { if (!u) return std::max(0ll, nw); if (nw < 0) return 0; if (fg && dp[u][nw] != -1) return dp[u][nw]; i64 ans = 0, up = (fg ? k - 1 : a[u]); for (int i = 0; i <= up; i++) { i64 cost; if (id == 1) { cost = i * (u - 1); } else if (u < id) { cost = -1 * i; } else { cost = i; } ans += dfs(u - 1, nw + cost, id, fg || (i != up)); } if (fg) dp[u][nw] = ans; return ans; } i64 calc(i64 x) { tot = 0; while (x) { a[++tot] = x % k; x /= k; } memset(dp, -1, sizeof(dp)); ans = dfs(tot, 0, 1, 0); for (int i = 2; i <= tot; i++) { memset(dp, -1, sizeof(dp)); ans -= dfs(tot, 0, i, 0); } return ans; } int main() { std::ios::sync_with_stdio(0); std::cin.tie(0), std::cout.tie(0); std::cin >> l >> r >> k; std::cout << calc(r) - calc(l - 1) << '\n'; return 0; }代码说明
dfs(u, nw, id, fg):数位DP搜索函数,计算合并到位置id的代价calc(x):计算区间内所有数字的最小代价之和- 主函数通过
calc(r) - calc(l-1)得到区间的结果
复杂度分析
- 时间复杂度:,其中为代价上限
- 空间复杂度:
- 1
信息
- ID
- 3674
- 时间
- 500ms
- 内存
- 32MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者