CF1101F Trucks and Cities

发布时间 2023-08-21 16:26:47作者: -白简-

题目大意

\(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,我们考虑优化。

  1. 考虑判一下记录的答案能否支持当前这辆车走完全程,如果可以,那就不用二分这辆车了,因为它的答案一定比原先的答案小,计算出来也不会更新答案。
  2. 对于第一条情况,我们把每辆车的顺序打乱重排能获得更优的期望复杂度。

跑的飞快,直接薄纱正解。

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;
}