习题:Trucks and Cities(双指针&DP)
题目
思路
对于每一辆车,
他的最小容量其实取决于最长的一段路,即我们可以通过求最长路来计算油量
设\(dp[i][j][k]\)为从\(i到j\)有\(k\)个加油站的最长路的最小值
状态转移比较明显
\(dp[i][j][k]=min\{max\{dp[i][ind][k-1],a[j]-a[ind]\}\}\)
这样的转移明显是\(O(n^4)\)的
我们考虑如果固定\(i和j和k\),
那么\(dp[i][ind][k]\)实际上是单增的,\(a[j]-a[ind]\)是单减的
对于\(dp[i][ind][k]>a[j]-a[ind]\)一段
我们一定是取最小的一个\(ind\),使得\(dp[i][ind][k]>a[j][ind]\)
对于\(dp[i][ind][k]<a[j]-a[ind]\)一段
我们一定是取最大的一个\(ind\),使得\(dp[i][ind][k]<a[j]-a[ind]\)
所以实际上我们只需要在这两个\(ind\)之间进行比较即可
如果我们固定\(i\)和\(k\),如果\(j\)增大,那么分界点一定也会增大
所以我们可以用一种类似于单调队列的指针来维护
最终的复杂度即为\(O(n^3)\)
代码
#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
int s,f,c,r;
int a[405];
int dp[401][401][401];
long long ans;
/*
区间i~j,设置k个油站
*/
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
dp[i][j][0]=a[j]-a[i];
for(int i=1;i<=n;i++)
{
for(int k=1;k<=n;k++)
{
int _ind=i;
for(int j=i+1;j<=n;j++)
{
dp[i][j][k]=dp[i][j][k-1];
while(dp[i][_ind][k-1]<=a[j]-a[_ind]&&_ind<j)
_ind++;
dp[i][j][k]=min(dp[i][j][k],min(dp[i][_ind][k-1],a[j]-a[_ind-1]));
}
}
}
for(int i=1;i<=m;i++)
{
cin>>s>>f>>c>>r;
r=min(r,n);
ans=max(ans,1ll*dp[s][f][r]*c);
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号