CF1101F Trucks and Cities 题解
来点神秘做法,复杂度是对的,而且会比 DP 优。
考虑逐个二分,发现复杂度 $O(nm\log V)$ 寄了。
考虑加点剪枝,发现若某段行程的答案 $\le$ 当前答案则不用对它二分,而这个判断可以 $O(n)$ 完成。
此时只会在每个前缀最大值处二分,发现答案递增还是会寄,
于是使用小杀招,shuffle 所有行程,此时前缀最大值只有 $\log m$ 个,总复杂度 $O(n\log m\log V+nm)$。
#include <cstdio>
#include <random>
#include <algorithm>
#define int long long
using namespace std;
int n, m, z, R, a[250050];
struct Q
{
int s, t, c, r;
} q[250050];
bool C(int o, int k)
{
for (int i = q[o].s, z = 0, p = 0; i < q[o].t; ++i)
{
if (q[o].c * (a[i + 1] - a[i]) > k)
return 0;
if (z + q[o].c * (a[i + 1] - a[i]) > k)
{
if (++p > q[o].r)
return 0;
z = q[o].c * (a[i + 1] - a[i]);
}
else
z += q[o].c * (a[i + 1] - a[i]);
}
return 1;
}
signed main()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%lld", a + i);
for (int i = 1; i <= m; ++i)
scanf("%lld%lld%lld%lld", &q[i].s, &q[i].t, &q[i].c, &q[i].r), R = max(R, q[i].c * (a[q[i].t] - a[q[i].s]));
shuffle(q + 1, q + m + 1, default_random_engine());
for (int i = 1, l, r, M; i <= m; ++i)
if (!C(i, z))
{
for (l = z, r = R; l <= r;)
if (C(i, M = l + r >> 1))
r = M - 1;
else
l = M + 1;
z = l;
}
printf("%lld", z);
return 0;
}