【题解】【CF1101F Trucks and Cities】

Analysis

首先很容易想到二分油箱大小,对每辆车O(n)贪心判断是否合法,复杂度是O(nmlogw)的,经过一些优化是可以通过的。
但这里要说一下dp解法。对于每辆车实际上我们要求从s到t分成r+1段,每一段的最大值最小是多少。这时可以用区间dp做的。
设f[i][j][k]表示从i到j分成k+1段每一段最大值最小是多少,考虑最后分的位置g,则有
f[i][j][k]=min(max(f[i][g][k-1],a[j]-a[g])),
这样直接做是N4的,我们可以利用单调性优化转移,
观察max中左边一项关于g单增,右边一项关于g单减,两者的max就是一个单谷函数,可以用三分来求最小值。
考虑进一步优化,当从小到大枚举k时,左边的一项整体单减,说明决策点单增,可以在枚举k的同时维护一个决策点,复杂度就优化成了N3
还有一点是,开三维数组极易超空间,考虑滚动数组,注意到每一个i都是无关的,因此可以直接去掉i这一维。

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int x=0,w=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') {w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=~(x-1);
if(x>9) write(x/10);
putchar('0'+x%10);
}
const int N=405;
int n,m,a[N],f[N][N],ans;
struct node{
int s,t,c,r;
bool operator<(const node &x)const{
if(s==x.s) return t<x.t;
return s<x.s;
}
}b[N*N*2];
signed main()
{
n=read();m=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=m;++i){
b[i].s=read();b[i].t=read();b[i].c=read();b[i].r=min(read(),b[i].t-b[i].s-1);
}
sort(b+1,b+m+1);
int cnt=1;
for(int i=1;i<n;++i)
{
if(i!=b[cnt].s) continue;
memset(f,0x3f,sizeof f);
f[i+1][0]=a[i+1]-a[i];
while(cnt<=m&&b[cnt].s==i&&b[cnt].t==i+1) ans=max(ans,f[i+1][0]*b[cnt].c),cnt++;
if(cnt>m) {write(ans);return 0; }
for(int j=i+2;j<=n;++j)
{
f[j][0]=a[j]-a[i];int pos=i;
for(int k=1;k<=j-i-1;++k)
{
while(max(f[pos][k-1],a[j]-a[pos])>max(f[pos+1][k-1],a[j]-a[pos+1])) pos++;
// if(pos==j) return 0;
f[j][k]=max(f[pos][k-1],a[j]-a[pos]);
}
while(cnt<=m&&b[cnt].s==i&&b[cnt].t==j) ans=max(ans,f[j][b[cnt].r]*b[cnt].c),cnt++;
if(cnt>m) {write(ans);return 0; }
if(b[cnt].s!=i) break;
}
}
return 0;
}
/*
10 2
2 3 4 8 9 10 12 13 15 19
3 9 2 0
4 10 3 0
*/
posted @   glq_C  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示