E. Antenna Coverage (dp)

传送门

题意: 在一个一维坐标上,有 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]);
}
View Code

 

posted on 2019-11-17 14:23  Willems  阅读(545)  评论(0编辑  收藏  举报

导航