石子合并——环形dp、区间dp
P1880 [NOI1995] 石子合并 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这道石子合并和之前的石子合并不一样。之前的那道题是一排石子合并,这道题是石子围成一圈合并。
那么问题就来了,围成一圈怎么进行合并处理呢?
以最大值为例,首先我们要明确,最后求得的是所有堆石子合并后的最大值。那么这个最大值满足最大值包含的每一区间都是该区间的最大值。可以反证,假设有一个区间的最大值不是这个最大值包含的那个区间最大值,那么累加之后的最大值应该大于原本的最大值。所以,问题就转化成求每一区间的最大值,最终就是所求的最大值。
注意1:因为石子围成了一圈,所以数组应该是个环,所以遍历的时候应该是从1到2n,并且前缀和应该从1到2n都算出来。
注意2:最后求的最值应该是for循环从1到n遍历一遍,maxx=max(maxx,f[i][i+n-1])这样的,因为是从1到n都要堆在一起。

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=400; 4 int a[N],s[N],f1[N][N],f2[N][N]; 5 6 int main() 7 { 8 int n;scanf("%d",&n); 9 for(int i=1;i<=n;i++) 10 { 11 scanf("%d",&a[i]); 12 a[i+n]=a[i]; 13 } 14 for(int i=1;i<=2*n;i++) 15 s[i]=s[i-1]+a[i]; 16 17 for(int len=1;len<=n;len++) 18 { 19 for(int i=1,j=len+i-1;i<=2*n,j<=2*n;i++,j=len+i-1) 20 { 21 if(i==j) 22 { 23 f1[i][j]=0; 24 f2[i][j]=0; 25 continue; 26 } 27 f2[i][j]=0x3f3f3f3f; 28 for(int k=i;k<j;k++) 29 { 30 f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]+s[j]-s[i-1]); 31 f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+s[j]-s[i-1]); 32 } 33 } 34 } 35 36 int minn=0x3f3f3f3f,maxx=-1; 37 for(int i=1;i<=n;i++) 38 { 39 minn=min(minn,f2[i][i+n-1]); 40 maxx=max(maxx,f1[i][i+n-1]); 41 } 42 printf("%d\n%d\n",minn,maxx); 43 44 return 0; 45 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现