石子合并

https://www.luogu.com.cn/problem/P1880

一道区间dp题目。

用d[i][j]表示从i到j的最大/最小得分,那么依次枚举长度len,坐标i和j,三层循环就可以dp递推求得最值了(听说这是道NOI题目)

记得使用前缀和哦。

复制代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctype.h>
#define INF 0x3f3f3f3f
using namespace std;
inline int read()
{
    int x=0,w=1;char c=getchar();
    while(!isdigit(c)){
        if(c=='-')w=-1;
        c=getchar();
    }
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*w;
}
const int maxn=105;
int a[maxn],sum[maxn],d[maxn][maxn],d2[maxn][maxn];
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];//前缀和 
    for(int len=2;len<=n;len++)
        for(int i=1;i<=n-len+1;i++)
        {
            int j=i+len-1;
            d[i][j]=INF;
            for(int k=i;k<j;k++)
            {
                if(d[i][j]>d[i][k]+d[k+1][j]+sum[j]-sum[i-1])
                d[i][j]=d[i][k]+d[k+1][j]+sum[j]-sum[i-1];
                if(d2[i][j]<d2[i][k]+d2[k+1][j]+sum[j]-sum[i-1])
                d2[i][j]=d2[i][k]+d2[k+1][j]+sum[j]-sum[i-1];
            }
                
        }
    printf("%d\n%d\n",d[1][n],d2[1][n]);
    return 0; 
}
复制代码

勇于实践的小伙伴们可以惊讶的发现:它爆零了!

emmm我们仔细审题会发现这是一个环。

所以不要着急我们给它再加n个数复制一遍就可以AC了(发扬了dp用内存换速度的优良作风)

复制代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctype.h>
#define INF 0x3f3f3f3f
using namespace std;
inline int read()
{
    int x=0,w=1;char c=getchar();
    while(!isdigit(c)){
        if(c=='-')w=-1;
        c=getchar();
    }
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*w;
}
const int maxn=105*2;
int a[maxn],sum[maxn],d[maxn][maxn],d2[maxn][maxn];
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)a[i]=a[i+n]=read();
    for(int i=1;i<=(n+n);i++)sum[i]=sum[i-1]+a[i];//前缀和 
    for(int len=2;len<=n;len++)
        for(int i=1,j=i+len-1;i<n+n and j<n+n ;i++,j=i+len-1)
        {
            d[i][j]=INF;
            for(int k=i;k<j;k++)
            {
                if(d[i][j]>d[i][k]+d[k+1][j]+sum[j]-sum[i-1])
                d[i][j]=d[i][k]+d[k+1][j]+sum[j]-sum[i-1];
                if(d2[i][j]<d2[i][k]+d2[k+1][j]+sum[j]-sum[i-1])
                d2[i][j]=d2[i][k]+d2[k+1][j]+sum[j]-sum[i-1];
            }
                
        }
    int ans1=INF,ans2=0;
    for(int i=1;i<=n;i++)ans1=min(ans1,d[i][i+n-1]),ans2=max(ans2,d2[i][i+n-1]);
    printf("%d\n%d\n",ans1,ans2);
    return 0; 
}
复制代码

当然,这个直接把n<<1的作死做法是没有办法干过大多数题目的。于是我们就需要对dp进行平行四边形优化

但是我没学……以后学了单独写一篇题解吧。

扩展:这道题的数据范围是n<=100,而我们给它还扩充到了n<=200。那么如果n更大呢?比如n<=40000?

这里有一道题目洛谷P5569

是的我们没法再用40000*40000的dp做了。

我也不会

这已经不是dp的问题了!但是还是给大佬们一个传送门

posted @   Star_Cried  阅读(149)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示