题目地址:
https://www.acwing.com/problem/content/364/
给定 n n n个区间 [ a i , b i ] [a_i,b_i] [ai,bi]和 n n n个整数 c i c_i ci。你需要构造一个整数集合 Z Z Z,使得 ∀ i ∈ [ 1 , n ] ∀i∈[1,n] ∀i∈[1,n], Z Z Z中满足 a i ≤ x ≤ b i a_i≤x≤b_i ai≤x≤bi的整数 x x x不少于 c i c_i ci个。求这样的整数集合 Z Z Z最少包含多少个数。
输入格式:
第一行包含整数
n
n
n。接下来
n
n
n行,每行包含三个整数
a
i
,
b
i
,
c
i
a_i,b_i,c_i
ai,bi,ci。
输出格式:
输出一个整数表示结果。
数据范围:
1
≤
n
≤
50000
1≤n≤50000
1≤n≤50000
0
≤
a
i
,
b
i
≤
50000
0≤a_i,b_i≤50000
0≤ai,bi≤50000
1
≤
c
i
≤
b
i
−
a
i
+
1
1≤c_i≤b_i-a_i+1
1≤ci≤bi−ai+1
设
s
[
i
]
s[i]
s[i]是在
1
∼
50001
1\sim 50001
1∼50001中,前
i
i
i个数中选了多少个数。为了方便我们将所有区间向右平移
1
1
1个单位,使得所有数都位于
[
1
,
50001
]
[1,50001]
[1,50001]里。那么
s
s
s需要满足以下条件:
1、
s
[
0
]
=
0
s[0]=0
s[0]=0;
2、
s
[
i
]
≥
s
[
i
−
1
]
,
s
[
i
]
−
s
[
i
−
1
]
≤
1
s[i]\ge s[i-1],s[i]-s[i-1]\le 1
s[i]≥s[i−1],s[i]−s[i−1]≤1,意思是
i
i
i这个数最多选
1
1
1次(因为题目里的
Z
Z
Z是个整数集合,集合是不能有重复元素的);
3、
s
[
b
i
]
−
s
[
a
i
−
1
]
≥
c
i
s[b_i]-s[a_i-1]\ge c_i
s[bi]−s[ai−1]≥ci,表示
[
a
i
,
b
i
]
[a_i,b_i]
[ai,bi]这个区间里取的数至少有
c
i
c_i
ci个。
这样就将原问题转化为了一个差分约束问题,要求的就是
s
[
50001
]
s[50001]
s[50001]的最小值,所以需要将每个不等式变为
s
[
x
]
≥
s
[
y
]
+
z
s[x]\ge s[y]+z
s[x]≥s[y]+z的形式,然后建图求最长路(从
y
y
y到
x
x
x连一条长
z
z
z的边即可),可以用SPFA来做。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 50010, M = 3 * N;
int n;
int h[N], e[M], ne[M], w[M], idx;
int dist[N];
int q[N];
bool st[N];
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void spfa() {
memset(dist, -0x3f, sizeof dist);
dist[0] = 0;
int hh = 0, tt = 0;
q[tt++] = 0;
st[0] = true;
// 循环队列里要写 while (hh != tt)
while (hh != tt) {
int t = q[hh++];
if (hh == N) hh = 0;
st[t] = false;
for (int i = h[t]; ~i; i = ne[i]) {
int v = e[i];
if (dist[v] < dist[t] + w[i]) {
dist[v] = dist[t] + w[i];
if (!st[v]) {
q[tt++] = v;
if (tt == N) tt = 0;
st[v] = true;
}
}
}
}
}
int main() {
scanf("%d", &n);
memset(h, -1, sizeof h);
for (int i = 1; i <= 50001; i++) {
add(i - 1, i, 0);
add(i, i - 1, -1);
}
while (n--) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
// 注意将所有区间向右平移一个单位
a++, b++;
add(a - 1, b, c);
}
spfa();
printf("%d\n", dist[50001]);
return 0;
}
时间复杂度 O ( n m ) O(nm) O(nm),空间 O ( n ) O(n) O(n), n n n和 m m m分别是图的点数和边数。