题意
题解
差分约束系统
间区间和转化为前缀和之差。设 S [ i ] S[i] S[i] 为区间 [ 0 , i ] [0,i] [0,i] 内数字的个数,则区间约数转化为 S [ b i ] − S [ a i − 1 ] ≥ c i S[b_i]-S[a_i-1]\geq c_i S[bi]−S[ai−1]≥ci,明显是一个差分约束系统的模型。不过,需要增加约数,以保证得到的解是有意义的。前缀和 S S S 单调不减,且长度为 1 1 1 的区间至多能选取 1 1 1 个数,即 S [ k ] − S [ k − 1 ] ≥ 0 , S [ k ] − S [ k − 1 ] ≤ 1 S[k]-S[k-1]\geq 0,S[k]-S[k-1]\leq1 S[k]−S[k−1]≥0,S[k]−S[k−1]≤1。
差分约束系统可以固定某个变量的取值,这里为
S
[
−
1
]
=
0
S[-1]=0
S[−1]=0,求出满足不等式组的一组可行解。但这里需要求解最小值,则将不等式转化为
X
i
−
X
j
≥
c
k
X_i-X_j\geq c_k
Xi−Xj≥ck 的形式,求解单源最长路;若需要求解最大值,则将不等式转化为
X
i
−
X
j
≤
c
k
X_i-X_j\leq c_k
Xi−Xj≤ck,求解单源最短路。
{
S
[
a
i
−
1
]
+
c
i
≤
S
[
b
i
]
S
[
k
]
−
1
≤
S
[
k
−
1
]
S
[
k
−
1
]
≤
S
[
k
]
\begin{cases}S[a_i-1]+c_i\leq S[b_i]\\ S[k]-1\leq S[k-1]\\ S[k-1]\leq S[k] \\ \end{cases}
⎩⎪⎨⎪⎧S[ai−1]+ci≤S[bi]S[k]−1≤S[k−1]S[k−1]≤S[k]
S
P
F
A
SPFA
SPFA 求解,总时间复杂度
O
(
N
2
)
O(N^2)
O(N2)。
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 50005, maxm = 3 * maxn, inf = 0x3f3f3f3f;
int N, lim, ds[maxn];
int tot, head[maxn], to[maxm], cost[maxm], nxt[maxm];
bool in[maxn];
inline void add(int x, int y, int z)
{
to[++tot] = y, cost[tot] = z, nxt[tot] = head[x], head[x] = tot;
}
void SPFA(int s)
{
for (int i = 0; i <= lim; ++i)
ds[i] = -inf, in[i] = 0;
ds[s] = 0, in[s] = 1;
queue<int> q;
q.push(s);
while (q.size())
{
int x = q.front();
q.pop(), in[x] = 0;
for (int i = head[x]; i; i = nxt[i])
{
int y = to[i], z = cost[i];
if (ds[x] + z > ds[y])
{
ds[y] = ds[x] + z;
if (!in[y])
in[y] = 1, q.push(y);
}
}
}
}
int main()
{
scanf("%d", &N);
lim = 0;
for (int i = 1, a, b, c; i <= N; ++i)
scanf("%d%d%d", &a, &b, &c), lim = max(lim, b + 1), add(a, b + 1, c);
for (int i = 1; i <= lim; ++i)
add(i, i - 1, -1);
for (int i = 1; i <= lim; ++i)
add(i - 1, i, 0);
SPFA(0);
printf("%d\n", ds[lim]);
return 0;
}
贪心 + BIT + 并查集
容易得到贪心策略,将三元组 ( a , b , c ) (a,b,c) (a,b,c) 按照 b b b 升序排序,顺序处理各个区间,尽可能地取靠后的数字,使之满足条件。
使用 B I T BIT BIT 维护区间和。使用并查集维护区间中还未取到的最大元素,具体而言,若取数字 i i i,则将 i i i 的父节点取为 i − 1 i-1 i−1,此时根节点就是区间中还未取到的最大元素。总时间复杂度 O ( N log N ) O(N\log N) O(NlogN)。
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 50005;
struct node
{
int a, b, c;
bool operator<(const node &o) const { return b < o.b; }
} A[maxn];
int N, lim, bit[maxn], fa[maxn];
int find(int x) { return fa[x] == x ? x : (fa[x] = find(fa[x])); }
void add(int i)
{
while (i <= lim)
++bit[i], i += i & -i;
}
int sum(int i)
{
int s = 0;
while (i)
s += bit[i], i -= i & -i;
return s;
}
int main()
{
scanf("%d", &N);
for (int i = 1, a, b, c; i <= N; ++i)
scanf("%d%d%d", &a, &b, &c), ++a, ++b, lim = max(lim, b), A[i] = node{a, b, c};
sort(A + 1, A + N + 1);
for (int i = 1; i <= lim; ++i)
fa[i] = i;
for (int i = 1; i <= N; ++i)
{
int t = A[i].c - (sum(A[i].b) - sum(A[i].a - 1)), j = A[i].b;
while (t > 0)
j = find(j), add(j), --t, fa[j] = j - 1;
}
printf("%d\n", sum(lim));
return 0;
}