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

posted @ 2025-05-05 12:19  onlyblues  阅读(70)  评论(0)    收藏  举报
Web Analytics