把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

Camels CodeForces - 14E【高维dp】

先扯两句 (似乎不止2句,qwq数学老师的风格)

高维dp的题是第一次遇到【甚至第一次在编程中用到四维数组】 高维dp由于维度比较高,考虑的东西比较多,所以比较麻烦【脑阔大】
然后由于我太limited了,所以扯一下大佬字字珠玑的博客

算法概述
顾名思义——一种处理多方面状态的DP,这种DP特点是……每一维的大小都不算太大(不然用dp数组存储下来内存会炸),而且枚举时容易超时……(一般来说,DP的复杂度为每一维的可取值之积。毕竟是乘积,很容易炸掉)。
众所周知,除了状压DP,一般的DP都是每一维表示了一个方面的状态,因此我们需要按照一定顺序枚举状态。
高维DP的大多数题中,各个方面的状态是互相关联、影响的,因此注意状态之间的互相限制是高维DP的难点,这也导致高维DP非常费脑子——状态转移方式奇多无比

大佬的链接
没错那个缠着大佬问问题的就是我,然后大佬解答之后很耐心地完善了博客 感谢大佬【紧紧抱住大佬大腿】
ღ( ´・ᴗ・` )比心


题意简述
n个数依次为A1~n,当且仅当第i个数( 1< i< n )满足 Ai-1< Ai 且 Ai> Ai+1 ,我们称Ai是一个驼峰;当且仅当 Ai-1> Ai 且 Ai< Ai+1 ,我们称 Ai 是一个谷底。已知 1≤ Ai≤ 4 ,求恰好形成t个驼峰的方案数。


分析

定义:dp[i][j][k][l]:第i个位置上的数为j,第i个数在第k个驼峰上(从上升段开始到下降段结束),l为1表示上升,0表示下降

注意分析状态定义需要的维度和状态时,要选取那些关键的部分。并不是找到所有的状态,那些关联很紧密(几乎一一对应的)就不需要用了,我们只需要找 相对有独立性但仍能影响其他状态的状态


转移
上升:

dp[i][j][k][1]=sigma(r=1,j-1) dp[i-1][r][k][1]+sigma(r=1,j-1)
dp[i-1][r][k-1][0]

dp[i-1][r][k][1]就是i和i-1在同一个驼峰上且都处于上升段,直接相加;
dp[i-1][r][k-1][0]就是i-1是前一个驼峰上的下降段的末尾(谷底),直接相加;

下降:

dp[i][j][k][0]=sigma(r=j+1,4)dp[i-1][r][k][0]+sigma(r=j+1,4)
dp[i-1][r][k][1]

dp[i-1][r][k][0]就是i-1和i在同一个驼峰上,都处于下降段,直接相加;
dp[i-1][r][k][1]就是i-1和i在同一个驼峰上,i-1处于上升段的末尾(驼峰),直接相加;


#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 20
#define MAXT 10
#define INF 0x3f3f3f3f
#define LL long long
LL dp[MAXN+5][5][MAXT+5][2];
int n,t;
int main()
{
    scanf("%d %d",&n,&t);
    //i==1的情况不用管,它只有一个数,看不出是上升还是下降,而且并没有什么作用,只是起个头
    dp[2][2][1][1]=1;//{1,2}
    dp[2][3][1][1]=2;//{1,3}{2,3}
    dp[2][4][1][1]=3;//{1,4}{2,4}{3,4}
    //初始化i==2可以防止一开始就是下降段的情况
    for(int i=3;i<=n;i++)
        for(int j=1;j<=4;j++)
            for(int k=1;k<=t;k++)
                for(int r=1;r<=4;r++)//枚举上一个数字
                {
                    if(r<j)
                        dp[i][j][k][1]+=dp[i-1][r][k][1];
                    if(r<j&&k>0)
                        dp[i][j][k][1]+=dp[i-1][r][k-1][0];
                    if(r>j)
                    {
                        dp[i][j][k][0]+=dp[i-1][r][k][0];
                        dp[i][j][k][0]+=dp[i-1][r][k][1];
                    }
                }
    LL ans=0;
    for(int i=1;i<=4;i++)
        ans+=dp[n][i][t][0];
    printf("%lld\n",ans);
}
posted @   Starlight_Glimmer  阅读(13)  评论(0编辑  收藏  举报  
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示