题解:P11520 [THUPC2025 初赛] 骑行计划

· · 题解

赛场上的想法感觉比较奇怪。

如果存在 (w',d',t')w'\le w,d'\ge d,t'\ge t,即这个操作就被偏序了,那么不妨把 (d,t) 操作的代价改为 w',因为如果选取的卡没有用满两个限制之一,答案不会更大。

于是可以把卡 (w,d,t) 看作一个 (d,t) 的权值为 w 的点,在矩形上对右上角 chkmin。这样就可以在想要的地方钦定这个操作出来。

然后考虑在 s_i 画成的柱状图上从上往下 dp,记 f_{t,l,r} 表示考虑柱状图 \ge t 的操作,区间 [l,r] 全部满足的最小代价。

设辅助数组 g_{l,r} 表示只考虑 s_i>t 的部分,区间 [l,r] 全部满足的最小代价。

- 直接用 $c$: $$g_{l,r}\gets g_{l,r-1}+\max\{0,a_r-t\}c$$ - 用操作。用 $\le t$ 的操作没用,所以直接从 $f_{t+1}$ 转移过来: $$g_{l,r}\gets\min\limits_k\{g_{l,r-k}+f_{t+1,r-k+1,r}\}$$ $f$ 的转移: - 直接用 $c$: $$f_{t,l,r}\gets f_{t,l,r-1}+a_rc$$ 这条转移只在 $t=1$ 合并答案时有用,$t>1$ 时虽然没错,但显然不优。 - 用 $\ge t+1$ 的操作完成: $$f_{t,l,r}\gets\min\limits_k\{f_{t,l,r-k}+f_{t+1,r-k+1,r}\}$$ - 新增长度为 $k$,高度为 $t$ 的操作: $$f_{t,l,r}\gets\min\limits_k\{f_{t,l,r-k}+w_{k,t}+g_{r-k+1,r}\}$$ 其中 $w_{k,t}$ 就是上述后缀 $\min$ 得到的数组。表示执行长度至少为 $k$,高度至少为 $t$ 的操作的最小代价。 直接转移即可,复杂度 $O(Vn^3)$。 --- 代码是赛场上随机写的。 ```cpp typedef long long ll; const int N=155; int n,m,c,V=150,a[N],w[N][N]; inline void C(ll&x,ll y){x>y&&(x=y);} ll f[N][N][N],g[N][N]; inline void main(){ scanf("%d%d%d",&n,&m,&c); for(int i=1;i<=n;i++)scanf("%d",&a[i]); memset(w,0x3f,sizeof w); for(int v,d,t;m--;){scanf("%d%d%d",&v,&d,&t);w[d][t]=min(w[d][t],v);} for(int i=n;i;i--)for(int j=V;j;j--)w[i][j]=min(w[i][j],min(w[i+1][j],w[i][j+1])); memset(f,0x3f,sizeof f); for(int t=V;t;t--){ memset(g,0x3f,sizeof g); for(int i=1;i<=n;i++)f[t][i][i-1]=g[i][i-1]=0; for(int l=1;l<=n;l++)for(int r=l;r<=n;r++){ g[l][r]=g[l][r-1]+(ll)max(0,a[r]-t)*c; for(int k=1;k<=r-l+1;k++)C(g[l][r],g[l][r-k]+f[t+1][r-k+1][r]); } for(int l=1;l<=n;l++)for(int r=l;r<=n;r++){ if(t==1)f[t][l][r]=f[t][l][r-1]+(ll)a[r]*c; for(int k=1;k<=r-l+1;k++) C(f[t][l][r],f[t][l][r-k]+min(w[k][t]+g[r-k+1][r],f[t+1][r-k+1][r])); } } printf("%lld\n",f[1][1][n]); } ```