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