CF1101F Trucks and Cities
题目大意
有 \(n\) 个城市坐落在一条数轴上,第 \(i\) 个城市位于位置 \(a_i\)。
城市之间有 \(m\) 辆卡车穿行。每辆卡车有四个参数:\(s_i\) 为起点编号,\(f_i\) 为终点编号,\(c_i\) 表示每行驶 \(1\) 个单位长度需要消耗的油量,\(r_i\) 表示可以在路途中加油的次数。
当卡车到达一个城市的时候可以将油加满(当然也可以不加),在路中无法加油,但是路途中总加油次数不能超过 \(r_i\)。
所有卡车的油箱都是一样大的,我们称它的容积为 \(V\)。试求一个最小的 \(V\),使得对于所有的卡车都存在一种方案,在路途中任意时刻油箱内的油量大于等于 \(0\) 且路途中总加油次数小于等于 \(r_i\) 的情况下从起点城市到达终点城市。
思路
模拟赛 T3,考场思路是直接二分,对每辆车进行二分,答案取每辆车答案的最大值,时间复杂度 \(\operatorname{O}(nm \log n)\)。
这样显然会 TLE,我们考虑优化。
- 考虑判一下记录的答案能否支持当前这辆车走完全程,如果可以,那就不用二分这辆车了,因为它的答案一定比原先的答案小,计算出来也不会更新答案。
- 对于第一条情况,我们把每辆车的顺序打乱重排能获得更优的期望复杂度。
跑的飞快,直接薄纱正解。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 550;
inline int read()
{
int x=0,f=1;char ch=getchar();
while( ch < '0' || ch > '9' ) {if( ch == '-' ) f=-1;ch=getchar();}
while( ch >= '0' && ch <= '9' ) {x=x*10+(ch-48);ch=getchar();}
return x*f;
}
int n,m;
long long pos[N];
struct Trip{
int s,t;
long long c,r;
}a[250500];
int Max[N][N];
int i;
bool Check(long long &V) {
long long dis,need,times = 0,remain = V;
if(Max[a[i].s][a[i].t] * a[i].c > V)
return 0;
for(int j = a[i].s;j < a[i].t; j++) {
dis = pos[j + 1] - pos[j];
need = dis * a[i].c;
if(need <= remain)
remain -= need;
else {
times ++;
remain = V - need;
}
}
if(times > a[i].r)
return 0;
return 1;
}
int main() {
#ifdef ONLINE_JUDGE == 1
freopen("drive.in","r",stdin);
freopen("drive.out","w",stdout);
#endif
n = read();
m = read();
for(int i = 1;i <= n; i++)
pos[i] = read();
for(int i = 1;i <= m; i++) {
a[i].s = read();
a[i].t = read();
a[i].c = read();
a[i].r = read();
}
for(int i = 1;i <= n; i++){
long long maxn = 0;
for(int j = i + 1;j <= n; j++) {
maxn = max(maxn,pos[j] - pos[j - 1]);
Max[i][j] = maxn;
}
}
random_shuffle(a + 1,a + m + 1);
long long ans = 0;
for(i = 1;i <= m; i++) {
if(Check(ans))
continue;
long long l = max(Max[a[i].s][a[i].t] * a[i].c,ans + 1);
long long r = (pos[a[i].t] - pos[a[i].s]) * a[i].c;
long long mid,res = r;
while(l <= r) {
mid = (l + r) >> 1;
if(Check(mid)) {
r = mid - 1;
res = mid;
}
else
l = mid + 1;
}
ans = max(ans,res);
}
cout << ans << "\n";
fclose(stdin);
fclose(stdout);
return 0;
}