AtCoder AT_abc404_g [ABC404G] Specified Range Sums
前言
赛时想到了差分约束,随手写了个 SPFA 结果挂的很惨……还是太菜了,赛后 Bellman-Ford 又调了半天。
题目大意
给定整数 N , M N,M N,M 和长度为 M M M 的三个整数序列 L = ( L 1 , L 2 , … , L M ) , R = ( R 1 , R 2 , … , R M ) , S = ( S 1 , S 2 , … , S M ) L=(L_1,L_2,\dots,L_M),R=(R_1,R_2,\dots,R_M),S=(S_1,S_2,\dots,S_M) L=(L1,L2,…,LM),R=(R1,R2,…,RM),S=(S1,S2,…,SM)。请判断是否存在一个长度为 N N N 的正整数序列 A A A 满足 ∀ 1 ≤ i ≤ M , ∑ j = L i R i A j = S i \forall 1\le i\le M,\sum_{j=L_i}^{R_i}A_j=S_i ∀1≤i≤M,∑j=LiRiAj=Si。如果存在输出序列所有元素之和的最小值,否则输出 -1
。
思路
我们不妨令 s i s_i si 表示 ∑ j = 1 i A i \sum_{j=1}^i A_i ∑j=1iAi,所以 ∀ 1 ≤ i ≤ M , s R i − s L i − 1 = S i \forall 1\le i\le M,s_{R_i}-s_{L_i-1}=S_i ∀1≤i≤M,sRi−sLi−1=Si。很自然地想到差分约束(例题:洛谷 P1993 小 K 的农场),即利用最长路中如果 x x x 向 y y y 连一条边权为 w w w 的边,那么满足 y ≥ x + w y\ge x+w y≥x+w 的性质解不等式。
关于差分约束的详细内容本文不再过多讲解,请自行搜索学习。
本题显然要跑最长路。我们来想一想,都需要连哪些边:
- L i − 1 → R i L_i-1\to R_i Li−1→Ri,边权为 S i S_i Si。
- R i → L i − 1 R_i\to L_i-1 Ri→Li−1,边权为 − S i -S_i −Si。
- i − 1 → i i-1\to i i−1→i,边权为 1 1 1。
所以,我们建了这样一张图,以 0 0 0 为源点跑 Bellman-Ford 最长路即可。(注:作者赛时使用 SPFA 挂的很惨,如果您知道为什么这道题只能使用 Bellman-Ford 或者 SPFA 需要注意什么,可以在评论区中回复!)
那么答案就是 s n s_n sn,即 0 0 0 到 n n n 的最长路。
现在分析无解情况:
- 该图中存在负环情况。
- S i < R i − L i + 1 S_i<R_i-L_i+1 Si<Ri−Li+1 的时候也不满足条件。
- s n s_n sn 为负无穷。
代码
提交记录:这里。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;int n, m;
long long dis[5010];
int vis[5010];
int sum[5010];struct edge
{int x, y, w;
} ;vector<edge> e;void add(int x, int y, int w)
{e.push_back((edge){x, y, w});
}bool bellman_ford(int s)
{memset(dis, -0x3f, sizeof(dis));dis[s] = 0;for (int i = 0; i <= n; i++){bool flag = false;for (int j = 0; j < e.size(); j++){int x = e[j].x;int y = e[j].y;int w = e[j].w;if (dis[x] >= -1e17 && dis[y] < dis[x] + w){dis[y] = dis[x] + w;flag = true;}}if (!flag) return false;}return true;
}int main()
{cin >> n >> m;for (int i = 1; i <= m; i++){int u, v, w;cin >> u >> v >> w;if (w < v - u + 1){cout << "-1" << endl;return 0;}int t = w - (v - u + 1);add(v, u - 1, -w);add(u - 1, v, w);
// cout << u - 1 << " " << v << endl;}for (int i = 1; i <= n; i++)add(i - 1, i, 1);if (bellman_ford(0) || dis[n] <= -1e17)cout << "-1" << endl;else{
// for (int i = 0; i <= n; i++)
// cout << dis[i] << " ";
// cout << endl; long long minn = 0;for (int i = 1; i <= n; i++)minn = min(minn, dis[i]);cout << dis[n] << endl;}return 0;
}
总结
这次的 G 很水,难度顶多 普及 + / 提高 \color{green}普及+/提高 普及+/提高,思维难度和代码实现难度都
求助
作者赛时使用 SPFA 挂的很惨,如果您知道为什么这道题只能使用 Bellman-Ford 或者 SPFA 需要注意什么,可以在评论区中回复!