Ybtoj 方块消除 (区间dp)
题意
给定 m 接下来两行两个长为 m 的序列,第一行代表的是 m 个不同的区间的颜色,第二行代表的是 m 个区间的长度。同颜色的方块每次可以一起消除,设消除了 x 个,那么得分就是 x2 消除后余下的序列会自动合并,直至序列为空,求最大得分。
分析
观察题意,合并序列,加分,最大值,联想一下合并石子,是不是区间 dp 的样子就出来了。 但是我们发现,这题不能直接令 dp_{(i,j)} = max{(dp_{i,k} + dp_{k+1,j}) 这样的转移,因为考虑到合并当前的小区间之后,可能新填充进来的是同色的,那么就得不偿失了,这显然是不行的。
考虑枚举最后一个方块消掉的时候,假设我们当前的区间是 [i,j] ,有两种可能:直接消掉他或者留着他和左边拼起来消掉。接下来考虑较难的第二种情况,那么我们不妨令 p 为从 j 同色向左最远的位置, q 为 p 左边 j 的颜色第一次出现的位置(我们此时讨论的是 i j 不同色,否则不会这样)。好了,那么现在有一点是可以确定下来的,就是我们一定要消掉 [q+1,p−1] 这一区间,因为留着它也不会更优。至此,我们终于引出了本题的核心的核心,第三维状态: dp(i,j,k) 表示原序列的右边再拼上 k 个颜色与右端点 j 相同的方块。
决策的过程就是要么直接删去该节点,要么就去找 p q 进行转移,详见代码。
本题真的很难,感性理解吧。
希望我BB了这么多真的把我自己说懂了(
#include<cstdio> #include<queue> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cctype> #include<vector> #include<string> using namespace std; int t,n,a[205],dp[205][205][205],dis[205]; int main(){ scanf("%d",&t); int cnt = 0; while(t--){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",a+i); for(int i=n;i;--i) for(int j=i+1;j<=n;++j) if(a[i] == a[j])dis[i]++; for(int i=n;i;--i) for(int j=i;j<=n;++j){ for(int k=i;k<j;++k) if(a[k] == a[j]) for(int l = 0;l <= dis[k];++l) dp[i][j][l] = max(dp[i][j][l],dp[k+1][j-1][0] + dp[i][k][l+1]); for(int p=0;p<=dis[j];++p) dp[i][j][p] = max(dp[i][j][p],dp[i][j-1][0] + (p+1)*(p+1)); } printf("Case %d: %d\n",++cnt,dp[1][n][0]); memset(dp,0,sizeof(dp)); memset(dis,0,sizeof(dis)); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现