题解:P11520 [THUPC 2025 初赛] 骑行计划
更好的阅读体验
题目可以形式化一下。
有一个直方图,第
i 列的高度为a_i ,初始全白。你可以花费c 的代价涂黑一个格子,或者花费w_i 的代价,涂黑一个宽d_i 高t_i 的矩形(矩形的下边界要和x 轴重合)。求涂黑整个直方图的最小代价。
区间 dp,从上往下做。设
那么我们可以考虑第
- 整列一个点一个点涂黑。
f_{x, l, r} \leftarrow f_{x, l+1, r} + \max(a_l - x, 0) \cdot c - 在下面框一个矩形。假设
g_{d, t} 表示可以覆盖d \times t 的矩形的w 最小的矩形。那么我们可以枚举框出来的矩形的长和宽。f_{x, l, r} \leftarrow f_{j, l, l+i-1} + f_{x, l+i, r} + g_{i, j}
复杂度
我们发现,第二个转移中
我们直接设
然后这道题就做完了,复杂度
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define N 156
using namespace std;
template <typename T> inline void chkmax(T &x,T y){x=x<y?y:x;}
template <typename T> inline void chkmin(T &x,T y){x=x<y?x:y;}
int n,m,c,mx,a[N],w[N],d[N],t[N],g[N][N],f[N][N][N],h[N][N][N];
main()
{
scanf("%lld%lld%lld",&n,&m,&c);
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
for(int k=0;k<N;k++)f[i][j][k]=g[j][k]=h[i][j][k]=1e15;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),chkmax(mx,a[i]);
for(int i=1,d,t,w;i<=m;i++)
scanf("%lld%lld%lld",&w,&d,&t),chkmin(g[d][t],w);
for(int i=n;i;i--)
for(int j=mx;j;j--)chkmin(g[i][j],min(g[i+1][j],g[i][j+1]));
for(int x=0;x<N;x++)
for(int i=0;i<=n;i++)f[x][i+1][i]=0;
for(int x=mx;~x;x--)
for(int l=n;l;l--)
{
for(int r=l;r<=n;r++)
{
chkmin(f[x][l][r],f[x][l+1][r]+max(0ll,a[l]-x)*c);
for(int i=1;i<=r-l+1;i++)
chkmin(f[x][l][r],h[l][i][x+1]+f[x][l+i][r]);
}
for(int i=1;i<=n-l+1;i++)
h[l][i][x]=min(f[x][l][l+i-1]+g[i][x],h[l][i][x+1]);
}
printf("%lld\n",f[0][1][n]);
return 0;
}