SP14846 GCJ1C09C - Bribe the Prisoners 题解
非常好区间 dp。
我们发现直接依题做是困难的,因此考虑反着做。
也即,假定起初那 \(Q\) 个牢房均为空,现在要将给定的 \(Q\) 的犯人插入其中,求最小代价。
然后我们发现这题和 P1775 很像,相当于每插入一个人,两段不相邻的牢房就被合并到了一起。
接着我们就考虑这玩意怎么做区间 dp。
状态:
令 \(dp_{i,j}\) 表示区间 \([id_i,id_j]\)(\(id_i\) 表示第 \(i\) 个空牢房的编号)的最小代价。
答案即为 \(dp_{1,Q}\)。
初始令 \(dp_{i,i}=0\),其余为 \(\infty\)。
转移:
首先按照基本套路,枚举中转点 \(k\) 将区间分为 \([i,k]\) 与 \([k+1,j]\),分别计算贡献。
然后我们在 dp 前预处理出每段牢房的人数和 \(num_i\),它的前缀和记为 \(sum_i\)。
因此合并 \(i\) 与 \(i+1\) 两端的代价即为 \(sum_i+sum_{i+1}+j-i-1\)。
上式中的 \(j-i-1\) 是除去当前插入的人之前插入的人的总和。
于是有转移方程:
\[dp_{i,j}=\min(dp_{i,j},dp_{i,k}+dp_{k+1,j}+sum_{j}-sum_{i-1}+j-i-1)
\]
然后这题就做完了。
#include<bits/stdc++.h> #define int long long using namespace std; const int N=1e4+5; int p,q,n; int id[N],num[N],sum[N]; int dp[N][N]; signed main(){ ios::sync_with_stdio(0); cin>>n; for(int t=1;t<=n;t++){ cin>>p>>q; for(int i=1;i<=q;i++) cin>>id[i]; id[++q]=p+1; for(int i=1;i<=q;i++) num[i]=id[i]-id[i-1]-1; memset(dp,0x3f,sizeof(dp)); for(int i=1;i<=q;i++) dp[i][i]=0,sum[i]=sum[i-1]+num[i]; for(int i=2;i<=q;i++){ for(int j=1;j+i-1<=q;j++){ int s=j,e=j+i-1; for(int k=s;k<=e-1;k++) dp[s][e]=min(dp[s][e],dp[s][k]+dp[k+1][e]); dp[s][e]+=sum[e]-sum[s-1]+e-s-1; } } cout<<"Case #"<<t<<": "<<dp[1][q]<<'\n'; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效