CF1101F Trucks and Cities

Solution

\(f[i][j][k]\) 表示一辆每公里耗油量为 \(1\) 的货车从 \(i\)\(j\) 中途加 \(k\) 次油最小的油箱容量。枚举起点 \(st\) 和加油的次数 \(k\) ,这样就固定了两维,显然有DP方程:

\[f[i][j][k]=\min\limits_{i\leq p\leq j}(\max(f[i][p][k-1],a[j]-a[p])) \]

这是 \(O(n^4)\) 的,但是我们发现 \(p\) 增加的时候, \(f[i][p][k-1]\) 是单增的, \(a[j]-a[p]\) 是单减的,所以可以找出区间的决策点,即对整个区间进行分治。

然后复杂度就变成了 \(O(n^3)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long

using namespace std;
const int N=405;
int n,m,a[N],f[N][N][N];//f[i][j][k]代表i到j分成k+1段

inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
}

void solve(int st,int k,int l,int r,int ql,int qr){
    if(l>r) return ;
    int mid=(l+r)>>1,opt=0,temp=0;
    for(int i=ql;i<=min(qr,mid);i++)
        if(!opt||max(a[mid]-a[i],f[st][i][k-1])<temp)
            temp=max(a[mid]-a[i],f[st][i][k-1]),opt=i;
    f[st][mid][k]=temp;
    solve(st,k,l,mid-1,ql,opt);
    solve(st,k,mid+1,r,opt,qr);
}

int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++) f[i][j][0]=a[j]-a[i];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            solve(i,j,i+1,n,i+1,n);
    ll ans=0;
    for(int i=1;i<=m;i++){
        int s=read(),t=read(),c=read(),r=read();
        ans=max(ans,1ll*f[s][t][r]*c);
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2020-09-09 20:16  jasony_sam  阅读(95)  评论(0编辑  收藏  举报