首页 > 技术文章 > [CF1253E] Antenna Coverage - dp

mollnn 2021-02-08 19:39 原文

[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;
}

推荐阅读