1 条题解
-
0
自动搬运
来自洛谷,原作者为

Alex_Wei
**搬运于
2025-08-24 21:49:04,当前版本为作者最后更新于2021-12-13 16:58:14,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
还算有趣的动态规划。遇到这种区间划分题首先考虑 DP,设 表示以第 个单词结尾为一行,且这一行长度为 的最小答案,那么有 ,其中 满足 。直接转移的复杂度为 (枚举 算出对应的 )。
不过我们注意到有很多 都是空值,说明这个定义有些劣。不妨修改定义,设 表示最后一行为 的答案,再设 表示 即 组成一行的长度,那么有:
$$f_{i,j}=\min_{p\in[1,i-j]}(f_{i-j,p}+|L_{i-j,p}-L_{i,j}|) $$此时时间复杂度优化为 ,但仍无法接受。接下来使用拆绝对值的技巧,即维护 表示 , 表示 ,那么对于 对应的转移位置 ,我们只需找到最后一个位置 使得 ,那么 可以由 关于 的前缀 加上 ,以及 关于 的后缀 减去 得到。
又因为固定 时, 随着 增大而增大,这说明 从 处转移时的 随着 增加而递增,因此对每个位置 在求出 维护一个转移指针即可做到平方。
const int N = 2e3 + 5; int n, m, ans = 2e9, L[N], pos[N], tot[N], f[N][N]; int len[N][N], pre[N][N], suf[N][N]; int main(){ cin >> m >> n; for(int i = 1; i <= n; i++) { cin >> L[i], L[i] += L[i - 1]; for(int j = i - 1; ~j; j--) { int cur = i - j - 1 + L[i] - L[j]; if(cur > m) break; tot[i]++; if(!j) f[i][tot[i]] = 0; else { f[i][tot[i]] = 2e9; while(pos[j] < tot[j] && len[j][pos[j] + 1] <= cur) pos[j]++; if(pos[j]) cmin(f[i][tot[i]], pre[j][pos[j]] + cur); if(pos[j] < tot[j]) cmin(f[i][tot[i]], suf[j][pos[j] + 1] - cur); } len[i][tot[i]] = cur; } pre[i][0] = suf[i][tot[i] + 1] = 2e9; for(int j = 1; j <= tot[i]; j++) pre[i][j] = min(pre[i][j - 1], f[i][j] - len[i][j]); for(int j = tot[i]; j; j--) suf[i][j] = min(suf[i][j + 1], f[i][j] + len[i][j]); if(i == n) for(int j = 1; j <= tot[n]; j++) cmin(ans, f[i][j]); } cout << ans << endl; return 0; }
- 1
信息
- ID
- 2523
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者