G - Specified Range Sums
G - Specified Range Sums
Problem Statement
You are given an integer $N$ and length-$M$ integer sequences $L=(L_1,L_2,\dots,L_M)$, $R=(R_1,R_2,\dots,R_M)$, and $S=(S_1,S_2,\dots,S_M)$.
Determine whether there exists a length-$N$ positive integer sequence $A$ satisfying the following condition. If such a sequence exists, find the minimum possible sum of $A$.
- $\displaystyle \sum_{j=L_i}^{R_i} A_j = S_i$ for all $i$ ( $1 \le i \le M$ ).
Constraints
- All input values are integers.
- $1 \le N,M \le 4000$
- $1 \le L_i \le R_i \le N$
- $1 \le S_i \le 10^9$
Input
The input is given from Standard Input in the following format:
$N$ $M$
$L_1$ $R_1$ $S_1$
$L_2$ $R_2$ $S_2$
$\vdots$
$L_M$ $R_M$ $S_M$
Output
If there does not exist a length-$N$ positive integer sequence $A$ satisfying the condition, print -1.
Otherwise, print the minimum possible sum of $A$ as an integer.
Sample Input 1
5 3
1 2 4
2 3 5
5 5 5
Sample Output 1
12
For example, $A=(1,3,2,1,5)$ satisfies the condition.
Its sum is $12$, which is the minimum possible.
Sample Input 2
1 2
1 1 1
1 1 2
Sample Output 2
-1
Sometimes no such $A$ exists.
Sample Input 3
9 6
8 9 8
3 6 18
2 4 19
5 6 8
3 5 14
1 3 26
Sample Output 3
44
解题思路
很板的差分约束,好几年没遇到过差分约束的题了。
由于有一堆等式约束(可以等价转换为不等式约束),目标又是最小化某个值,因此容易想到差分约束。在求最小值的差分约束中(相当于求最长路),每个不等式约束都是 $x_i \geq x_j + c$ 的形式,其中 $x_i$ 和 $x_j$ 是变量,$c$ 是常数。但在本题中每个等式约束 $A_{L_i} + A_{L_i+1} + \cdots + A_{R_i} = S_i$ 含有多个变量,无法转换成上述的形式。由于都是连续元素的求和,我们可以用前缀和进行转换,定义 $s_i = \sum\limits_{j=1}^{i}{A_j}$,这样每个等式约束就等价变成 $s_{R_i} - s_{L_i-1} = S_i$。接着我们把等式约束等价变成两个不等式约束,即
$$\begin{cases}
s_{R_i} - s_{L_i-1} \geq S_i \\
s_{R_i} - s_{L_i-1} \leq S_i \\
\end{cases}
\Rightarrow
\begin{cases}
s_{R_i} \geq s_{L_i-1} + S_i \\
s_{L_i-1} \geq s_{R_i} - S_i \\
\end{cases}$$
相应的,我们从最小化目标 $\sum\limits_{i=1}^{n}{A_i}$ 等价变成了最小化 $s_n$。另外题中还有 $A_i$ 是正整数的约束,这个等价于 $s_{i} - s_{i-1} \geq 1 \Rightarrow s_{i} \geq s_{i-1} + 1 \, (1 \leq i \leq n)$。同时我们规定 $s_0 = 0$。
接着就是建图跑最长路了,对于每个形式为 $x_i \geq x_j + c$ 的约束,我们连一条从 $j$ 到 $i$ 边权为 $c$ 的边。需要注意的是,在跑最长路的过程中要保证每条边都能被访问到,这等价于每个约束都要考虑到,否则求出的结果不能保证正确性了。因此我们将 $0$ 号点 $s_0$ 作为虚拟源点,向每个 $i \, (1 \leq i \leq n)$ 连一条边权为 $1$ 的边(对应约束 $s_i \geq s_0 + 1$),只要能访问所有点就能保证访问所有边。
最后我们从 $s_0$ 出发用 spfa 跑最长路,如果存在正环(等价于从源点 $0$ 出发到某个点经过的边数超过 $n$)则无解。否则最后的答案就是从 $0$ 出发到 $n$ 的最长距离。
AC 代码如下,时间复杂度为 $O(nm)$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 4005, M = 1e5 + 5;
int n, m;
int h[N], e[M], wt[M], ne[M], idx;
LL d[N], c[N];
bool vis[N];
void add(int u, int v, int w) {
e[idx] = v, wt[idx] = w, ne[idx] = h[u], h[u] = idx++;
}
bool spfa() {
memset(d, -0x3f, sizeof(d));
d[0] = 0;
queue<int> q({0});
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if (d[v] < d[u] + wt[i]) {
d[v] = d[u] + wt[i];
c[v] = c[u] + 1;
if (c[v] > n) return false;
if (!vis[v]) {
vis[v] = true;
q.push(v);
}
}
}
}
return true;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
memset(h, -1, sizeof(h));
while (m--) {
int l, r, s;
cin >> l >> r >> s;
add(l - 1, r, s);
add(r, l - 1, -s);
}
for (int i = 1; i <= n; i++) {
add(i - 1, i, 1);
add(0, i, 1);
}
if (!spfa()) cout << -1;
else cout << d[n];
return 0;
}
参考资料
Editorial - AtCoder Beginner Contest 404:https://atcoder.jp/contests/abc404/editorial/12867
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18860011

浙公网安备 33010602011771号