[CF1253E] Antenna Coverage

[CF1253E] Antenna Coverage - dp

Description

街道上有 (n le 80) 个天线。第 (i) 个天线的位置为 (x_i),以及一个范围值 (s_i);第 (i) 个天线的覆盖范围是 ([x_i-s_i,x_i+s_i])。每次操作,你可以花费 (1) 代价,使得第 (i) 个天线的 (s_i) 增加一。每个天线都可以进行多次操作。现在请问你最少需要花费多少代价,使 ([1,m] (m le 10^5)) 编号内的每一个位置都被至少一个天线覆盖。

Solution

(f[i]) 表示 ([1,i]) 被全部覆盖的最小花费,初态 (f[i]=i)

如果 i 已经被某个初始区间完全覆盖了,那么可以从 (f[i-1]) 转移过来

另一种转移是,有一个区间要扩张,枚举每个区间,这里我们只取左边的区间向右扩张

如果区间的右端点在 i 左边,那么可以考虑这个区间扩张后恰好覆盖到 i 的左端点的情况,也就是从 (f_{l_j-i+r_j)+i-r_j) 转移过来

为什么不同时取右边的区间向左扩张?假设方案中右边有个区间在后面扩张了,那么转移的时候取的转移来源会更偏左……,因此,对于同一个点而言,转移到它的所有状态中,转移点靠右的状态一定不会更劣

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 100005;

signed main()
{
    ios::sync_with_stdio(false);

    int n, m;
    cin >> n >> m;

    vector<int> x(n + 2), s(n + 2), l(n + 2), r(n + 2), f(m + 2);
    for (int i = 1; i <= m; i++)
        f[i] = i;
    for (int i = 1; i <= n; i++)
    {
        cin >> x[i] >> s[i];
        l[i] = x[i] - s[i];
        r[i] = x[i] + s[i];
    }
    for (int i = 1; i <= m; i++)
    {
        int flag = 0;
        for (int j = 1; j <= n; j++)
            if (l[j] <= i && r[j] >= i)
                flag = 1;
        if (flag)
        {
            f[i] = f[i - 1];
        }

        for (int j = 1; j <= n; j++)
        {
            if (r[j] < i)
            {
                f[i] = min(f[i], f[max(0ll, l[j] - i + r[j] - 1)] + i - r[j]);
            }
        }
    }
    cout << f[m] << endl;
}
原文地址:https://www.cnblogs.com/mollnn/p/14390176.html