#前缀和 #序列dp #单调队列 首先每一行需要花费的成本是不变的,而这里是选择连续的 $k$ 行,因此可以使用前缀和优化。那么我们就需要对每一行求解。 假设当前行的数组为 $a$,那么设 $dp_i$ 表示为修桥修到 $i$ 的成本,这个值就等于所有距离小于等于 $d$ 的 $j$,当中 $dp_j$ 的最小值加上 $a_i+1$。但是这题 $d\le 2\times 10^5$,因此我们需要使用单调队列优化。由于好渴鹅懒得写单调队列,因此直接使用优先队列。 时间复杂度 $\mathcal O(n\times m\log_2 d)$。 ```cpp #include <iostream> #include <utility> #include <queue> using namespace std; using LL = long long; const LL kMaxN = 105, kMaxM = 2e5 + 5; LL a[kMaxN][kMaxM], dp[kMaxM], p[kMaxN], t, n, m, k, d, ans; priority_queue<pair<LL, LL>, vector<pair<LL, LL>>, greater<>> q; void solve(LL x) { for (; q.size(); q.pop()) { } q.emplace(a[x][1] + 1, 1); for (LL i = 2; i <= m; i++) { for (; q.top().second < i - d - 1; q.pop()) { } q.emplace(q.top().first + a[x][i] + 1, i); } for (; q.top().second != m; q.pop()) { } p[x] = q.top().first; } int main() { for (cin >> t; t; t--) { cin >> n >> m >> k >> d; ans = 1e18; for (LL i = 1; i <= n; i++) { for (LL j = 1; j <= m; j++) { cin >> a[i][j]; } } for (LL i = 1; i <= n; i++) { solve(i); p[i] += p[i - 1]; } for (LL i = k; i <= n; i++) { ans = min(ans, p[i] - p[i - k]); } cout << ans << '\n'; } return 0; } ```