题意
给出nnn个形如“a b c”“a\ b\ c”“a b c”的式子,表示在aaa和bbb之间至少有ccc个不同的数。求出满足这nnn个条件的序列的最小长度。
思路
设d[i]d[i]d[i]为0∼i0\sim i0∼i的数字中有多少个在序列里,由题意得db−da−1≥cd_b-d_{a-1}\geq cdb−da−1≥c。
我们可以发现,这个式子很像最短路中的松弛操作dv>=du+w(u,v)d_v>=d_u+w(u,v)dv>=du+w(u,v)。那么我们把上面得出的式子移项,变成db≥da−1+cd_b\geq d_{a-1}+cdb≥da−1+c,于是我们就可以在a−1a-1a−1和bbb中建一条长度为ccc的边。
由于ddd是有联系的,我们还发现两个条件di−di−1>=0;di−1−di>=−1d_i-d_{i-1}>=0;d_{i-1}-d_i>=-1di−di−1>=0;di−1−di>=−1。
按照这样建图后,根据db≥da−1+cd_b\geq d_{a-1}+cdb≥da−1+c,我们就可以跑最长路求出ddd。
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
int n, tot, s = 50000, t;
int head[50001], next[150001], ver[150001], edge[150001], v[50001], d[50001];
void add(int u, int v, int w) {
ver[++tot] = v;
next[tot] = head[u];
edge[tot] = w;
head[u] = tot;
}
void spfa() {
std::queue<int> q;
memset(d, -127 / 3, sizeof(d));
v[s] = 1;
d[s] = 0;
q.push(s);
while (q.size()) {
int u = q.front();
q.pop();
v[u] = 0;
for (int i = head[u]; i; i = next[i]) {
int to = ver[i];
if (d[to] < d[u] + edge[i]) {
d[to] = d[u] + edge[i];
if (!v[to]) {
v[to] = 1;
q.push(to);
}
}
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
s = std::min(s, x - 1);
t = std::max(t, y);
add(x - 1, y, z);
}
for (int i = s + 1; i <= t; i++) {
add(i, i - 1, -1);
add(i - 1, i, 0);
}
spfa();
printf("%d", d[t]);
}