CF1175E Minimal Segment Cover

思路

这是一道简单的 DP 题,DP 题的核心就是状态转移。

先来说一说 dpdp 数组的含义。

dpi,jdp_{i,j} 表示从 ii 这个点用 2j2 ^ j 条线段能走到的最远的点。

我们再来考虑一下边界情况。

因为我们只用 202 ^ 0 条线段,那么:dpi,0=max(dpi,0,r)dp_{i,0} = \max(dp_{i,0},r)

接着,我们递推一遍,从前往后更新一遍最大值。

即:dpi,0=max(dpi,0,dpi1,0)dp_{i,0} = \max(dp_{i,0},dp_{i - 1,0})

然后我们对 dpdp 数组进行递增。

即:dpj,i=dpdpj,i1,i1dp_{j,i} = dp_{dp_{j,i - 1},i - 1}

注:以上递推和递增的操作都需要从 11NN,原因是:我们操作都是预处理,最后直接求答案的。

最后,我们直接用一个循环来求出答案。

如果 dpx,i<ydp_{x,i} < y,那么我们的结果直接加上 2i2 ^ i,将 xx 更新为 dpx,idp_{x,i}

结果要加上 2i2 ^ i 的原因是:我们从 dpdp 数组的含义出发,我们需要的线段数量便是 2i2 ^ i

xx 更新成 dpx,idp_{x,i} 的原因是:我们把点 xx 之前的所有点都走过了,所以我们直接更新即可

我们最后算出来的结果是终点的上一个点,所以我们需要判断一下最后一个是否有解就行了,如果有解输出结果 + 1,否则输出 -1

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <bits/stdc++.h>  

using namespace std;

const int N = 5e5 + 10;
int n,m;
int dp[N + 100000/*要开大一点,不然越界*/][25];

int main(){
cin >> n >> m;
for (int i = 1;i <= n;i++){
int a,b;
cin >> a >> b;
dp[a][0] = max(dp[a][0],b);
}
for (int i = 1;i <= N;i++) dp[i][0] = max(dp[i][0],dp[i - 1][0]);
for (int i = 1;i <= 19;i++){
for (int j = 0;j <= N;j++){
dp[j][i] = dp[dp[j][i - 1]][i - 1];
}
}
while (m--){
int x,y;
int res = 0;
cin >> x >> y;
for (int i = 19;i >= 0;i--){
if (dp[x][i] < y){
res += (1 << i);
x = dp[x][i];
}
}
if (dp[x][0] >= y) cout << res + 1 << endl;
else puts("-1");
}
return 0;
}

CF1175E Minimal Segment Cover
http://watersun.top/[题解]CF1175E Minimal Segment Cover/
作者
WaterSun
发布于
2024年6月12日
许可协议