題意: 在一個一維坐標上,有 n 個東西, 每個東西, 用 xi, si 表示 這個東西在 xi 位置上,
它能覆蓋到的區間為 [ xi - si, xi + si ];
然后, 你可以對任意的東西, 擴大它的 覆蓋區間, 即對 si 加 1; 花費1;
問你 覆蓋 [ 1, m ] 的最少花費。
n <= 80, m <= 100000;
解: 顯然 DP;
我們用 dp[ i ] 表示 覆蓋 i ~ m 的最少花費。
然后我們從 m ~ 1 枚舉 x;
若這個x 被某個東西覆蓋, 則 dp[ i ] = dp[ i + 1 ];
否則, 枚舉 所有的 n 個東西, 判斷 那些 xi - si 大於你當前枚舉的那個 x 的東西。
那么你設 dis = xi - si - x; 即你到那個東西覆蓋的區間的左端點的距離。
然后, 因為它左邊擴了 dis, 那么它右邊也可以擴 dis;
那么,答案就是 dis + dp[ xi + si + dis];
然后, 最后 dp[ 1 ] 就是答案了。

#include <bits/stdc++.h> #define LL long long #define INF 0x3f3f3f3f using namespace std; struct note { int l, r; }a[100]; bool cmp(note a, note b) { return a.l == b.l ? a.r < b.r : a.l < b.l; } const int N = 2e5 + 5; int dp[N]; int main() { int n, m; scanf("%d %d", &n, &m); for(int i = 0; i <= m; i++) dp[i] = INF; int ma = 0; for(int i = 1; i <= n; i++) { int x, s; scanf("%d %d", &x, &s); a[i].l = max(x - s, 1); a[i].r = min(x + s, m); ma = max(ma, a[i].r); for(int j = a[i].l; j <= a[i].r; j++) { dp[j] = 0; } } for(int i = m; i > ma; i--) dp[i] = m - i + 1; // n++; a[n].l = n; a[n].r = n; sort(a + 1, a + 1 + n, cmp); dp[m + 1] = 0; for(int i = m; i >= 1; i--) { if(dp[i] == 0) dp[i] = dp[i + 1]; else { for(int j = 1; j <= n; j++) { if(a[j].l > i) { int dis = a[j].l - i; int R = min(a[j].r + dis, m); dp[i] = min(dp[i], dis + dp[R + 1]); } } } } printf("%d\n", dp[1]); }