zhaoxinwei666 2024-05-23 09:06 采纳率: 0%
浏览 10
已结题

求各位解释一道区间DP

请假一道区间DP题目的思路 ,是安徽省信息学省赛初中组第4题
题目描述

img


官方题解是这样的:
考虑怎么判断一个序列是不是好的:我们设 fi 表示能不能将 1 到 i 全部消完,考虑 i 和哪一个元素一起消掉,发现如果有 aj = ai 且 fj−1 = 1,则 fi = 1,否则 fi = 0。
考虑根据这个结论设计 dp,我们设 dpi,j,k 表示到了第 i 个位置,有 j 个值满足存在至少一个位置 p 使得 ap = v 且 fp−1 = 1,fi−1 = k。
每次考虑第 i 个位置的值时,只要考虑 fi 是否等于 1,以及是否新增了一个ai = v 且 fi−1 = 1 的值即可。
理解了状态,转移是不难写出来的。
这是正确代码,能详细解释下么:

#include<bits/stdc++.h>
using namespace std;
const int N=3005,mod=1e9+7;
int n,m,f1[N][N],f0[N][N];
int main(){
    cin>>n>>m;
    f1[0][0]=1;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<=i;j++){
            f1[i+1][j]=(f1[i+1][j]+1ll*f1[i][j]*j)%mod;
            f1[i+1][j]=(f1[i+1][j]+1ll*f0[i][j]*j)%mod;
            f0[i+1][j+1]=(f0[i+1][j+1]+1ll*f1[i][j]*(m-j))%mod;
            f0[i+1][j]=(f0[i+1][j]+1ll*f0[i][j]*(m-j))%mod;
        }
    }
         
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        ans+=f1[n][i];
        ans%=mod;
    }
 
    cout<<ans;
    return 0;
}

不要aigc生成,说点人话
  • 写回答

11条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-05-23 09:07
    关注

    引自免费微信小程序:皆我百晓生

    题目要求计算所有可能的糖果序列中,有多少序列可以被小可可全部吃完。我们可以使用动态规划的方法解决这个问题。

    首先,我们需要定义状态。状态dpi,j,k表示到达第i个位置时,已经有j种不同的颜色,并且其中k种颜色的糖果前面已经有一段连续的同色糖果被吃掉,即存在p<p'使得ap=ap'=v且fp-1=1。

    初始状态为f0[0][0]=1,表示没有糖果的情况下,满足条件的序列只有空序列。

    接下来,我们进行状态转移。对于每个位置i,我们要考虑两种情况:

    1. 如果当前糖果的颜色和前一个已经被标记为连续的某颜色相同(即fi-1=k),那么这种情况下的贡献为f1[i-1][j-1]*(m-k),因为剩下的颜色种类数为m-k,我们可以选择其中任意一种颜色作为新的开始,形成一个新的连续区域。
    2. 如果当前糖果的颜色是新出现的颜色(即fi-1=0),那么这种情况下的贡献为f0[i-1][j]*(m-j),因为我们又增加了一种颜色,且之前的颜色序列都不连续。

    因此,状态转移方程可以表示为:

    f0[i][j] = (f0[i][j] + f0[i-1][j]*(m-j)) % mod f1[i][j] = (f1[i][j] + f1[i-1][j]*j + f0[i-1][j]j + f1[i-1][j-1](m-k)) % mod

    这里,k是之前连续颜色的数量,可以通过遍历找到。但是,为了简化计算,我们可以利用以下性质:

    • 当前颜色与前一颜色不同(即fi-1=0),则f1[i][j] += f0[i-1][j]*(m-j)
    • 当前颜色与前一颜色相同(即fi-1=1),则f1[i][j] += f1[i-1][j]*j + f0[i-1][j]*j

    这是因为,如果颜色相同,前一颜色的连续性保持不变,所以贡献为f1[i-1][j]*j;而如果颜色不同,前一颜色的连续性结束,但新的颜色可能成为连续颜色的一部分,所以贡献为f0[i-1][j]*j。

    最后的答案是所有可以被吃完的序列数量,即所有f1[n][i]之和对模1e9+7取余的结果。以下是完整的代码实现:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=3005, mod=1e9+7;
    int n,m,f1[N][N],f0[N][N];
    
    int main(){
        cin>>n>>m;
        f1[0][0]=1;
        
        // 初始化连续颜色的情况
        for(int j=0; j<=n; ++j){
            f0[0][j] = (j==0)? 1 : 0;
        }
    
        for(int i=1; i<=n; i++){
            for(int j=0; j<=i; j++){
                f1[i][j] = (f1[i][j] + f1[i-1][j]*j + f0[i-1][j]*j) % mod;
                f0[i][j] = (f0[i][j] + f0[i-1][j]*(m-j)) % mod;
            }
        }
             
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            ans=(ans+f1[n][i])%mod;
        }
     
        cout<<ans;
        return 0;
    }
    

    这段代码实现了上述的动态规划算法,计算出了满足条件的糖果序列总数,并返回了对1e9+7取余后的结果。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 5月23日
  • 修改了问题 5月23日
  • 创建了问题 5月23日

悬赏问题

  • ¥15 如何解除Uniaccess管控
  • ¥15 微信小程序跳转关联公众号
  • ¥15 Java AES 算法 加密采用24位向量报错如何处理?
  • ¥15 使用X11可以找到托盘句柄,监控到窗口点击事件但是如何在监听的同时获取托盘中应用的上下文菜单句柄
  • ¥45 字符串操作——数组越界问题
  • ¥15 Loss下降到0.08时不在下降调整学习率也没用
  • ¥15 QT+FFmpeg使用GPU加速解码
  • ¥15 为什么投影机用酷喵播放电影放一段时间就播放不下去了?提示发生未知故障,有什么解决办法吗?
  • ¥15 来个会搭建付费网站的有偿
  • ¥100 有能够实现人机模式的c/c++代码,有图片背景等,能够直接进行游戏