当前位置: 代码迷 >> 综合 >> 【 Educational Codeforces Round 58 (Rated for Div. 2) F. Trucks and Cities】 DP+单调队列优化
  详细解决方案

【 Educational Codeforces Round 58 (Rated for Div. 2) F. Trucks and Cities】 DP+单调队列优化

热度:99   发布时间:2023-12-29 02:11:00.0

题目链接

F. Trucks and Cities

题意

有n个城市在x轴上,有m辆卡车,每辆卡车有四个属性,分别是起始城市s,终止城市f,每公里消耗燃料燃料消耗c,和可加油次数r。每次加油卡车油量加满,卡车的油量为V,所有卡车初始油量都是满的。求能让所有卡车从起点到达终点的最小油量V。

2&lt;=n&lt;=400,1&lt;=m&lt;=2500002&lt;=n&lt;=400,1&lt;=m&lt;=2500002<=n<=400,1<=m<=250000
1&lt;=ai&lt;=109,ai&lt;ai+11&lt;=a_i&lt;=10^9,a_i&lt;a_{i+1}1<=ai?<=109,ai?<ai+1?
做法

首先考虑暴力的n4n^4n4的做法。设dp[i][j][k]dp[i][j][k]dp[i][j][k]为 从iii出发到达jjj休息kkk次的最小间隔。
dp[i][j][k]=min?j?1l=i+1(max?(dp[i][l][k?1],a[j]?a[l]))dp\left[ i \right] \left[ j \right] \left[ k \right] =\underset{l=i+1}{\overset{j-1}{\min}}\left( \max \left( dp\left[ i \right] \left[ l \right] \left[ k-1 \right] ,a\left[ j \right] -a\left[ l \right] \right) \right) dp[i][j][k]=l=i+1minj?1?(max(dp[i][l][k?1],a[j]?a[l]))
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 405;
int dp[maxn][maxn][maxn]; // dp[i][j][k] 表示从i出发到达j中间停留k次的最长间隔。
int a[maxn];
int main()
{
    int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=1;i<=n;i++){
    for(int j=i+1;j<=n;j++){
    dp[i][j][0]=a[j]-a[i];for(int k=1;k<=n;k++){
    dp[i][j][k]=a[j]-a[i];for(int l=i+1;l<j;l++){
    dp[i][j][k]=min(dp[i][j][k],max(dp[i][l][k-1],a[j]-a[l]));}}}}ll ans=0;for(int i=1;i<=m;i++){
    int s,f,c,r;scanf("%d%d%d%d",&s,&f,&c,&r);ans=max(ans,1LL*dp[s][f][r]*c);}printf("%lld\n",ans);return 0;
}

首先我们可以滚动掉第一维,之后我们可以发现,
max?(dp[i][l][k?1],a[j]?a[l])\max \left( dp\left[ i \right] \left[ l \right] \left[ k-1 \right] ,a\left[ j \right] -a\left[ l \right] \right) max(dp[i][l][k?1],a[j]?a[l])
这个是满足决策单调性的,我们只需要一个单调队列维护,复杂度就变为n3n^3n3

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 405;
int dp[maxn][maxn]; // dp[i][j][k] 表示从i出发到达j中间停留k次的最长间隔。
int a[maxn];
int pos[maxn];
struct data
{
    int f,c,r;data(){
    }data(int ff,int cc,int rr){
    f=ff;c=cc;r=rr;}
};
vector<data> G[maxn];
int main()
{
    int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=1;i<=m;i++){
    int s,f,c,r;scanf("%d%d%d%d",&s,&f,&c,&r);G[s].push_back(data(f,c,r));//离线处理每个起点为s的查询}ll ans=0;for(int i=1;i<=n;i++){
    for(int j=i+1;j<=n;j++){
    dp[j][0]=a[j]-a[i];int pos=0;for(int k=1;k<=n;k++){
    dp[j][k]=a[j]-a[i];while(pos+1<=j&&dp[pos+1][k-1]<a[j]-a[pos+1]) pos++;//单调队列优化DPdp[j][k]=min(dp[j][k],min(a[j]-a[pos],dp[pos+1][k-1]));}}for(int j=0;j<G[i].size();j++){
    int f=G[i][j].f;int c=G[i][j].c;int r=G[i][j].r;ans=max(ans,1LL*dp[f][r]*c);}}printf("%lld\n",ans);return 0;
}
  相关解决方案