序列

博客探讨了序列构造问题,通过动态规划(dp)解决长度为i的序列,最大值不超过j的方案数。利用前缀和pre[i][j]进行状态转移,公式为dp[i][j]=(dp[i][j]+dp[i-l][j]*pre[l][j-1]*C(i-2,l-1))。初始状态设置dp[1][0,1,...,k]=1。" 127752368,15263787,LeetCode解题日记:两数相加,"['算法', '链表', 'LeetCode']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

序列
monyhzc (感谢他让我明白了)
————————————————————————————————————
我们先观察,发现每次只会从上一个序列多增一个数,其实就是说是将原序列复制一遍,并在适当位置添上一个数,还要保证添上的数大于后面的一个数,其实我们可以认为是将原序列中的一个数前面长出一个比它大的数

因为最后一个位置不好算长出来,所以我们可以在序列末尾补一个0,这样我们就可以表示最后一个位置长出来了
—————————————————————————————————————
(这个dp思路太难想了)

dp[i][j]表示长度为i的序列最大值不大于j的方案数,pre[i][j]表示dp[i][1-j]的前缀和

(其实就是两个前缀)
考 虑 如 何 转 移 d p [ i ] [ j ] 考虑如何转移dp[i][j] dp[i][j]
在这里插入图片描述
我 们 先 枚 举 一 个 x , 保 证 x 前 的 数 是 由 x 长 出 来 的 , 即 后 面 的 方 案 数 为 p r e [ i − l ] [ x − 1 ] , 即 后 面 的 最 大 值 不 超 过 x , 前 面 的 可 以 随 便 选 数 , 为 d p [ i − l ] [ x ] 因 为 相 当 于 我 们 已 经 有 一 个 x , 0 , 的 序 列 , 长 度 为 2 , 我 们 可 以 在 0 前 面 和 x 前 面 选 数 , 即 已 经 有 2 个 时 间 填 了 数 , 所 以 总 共 有 i − 2 个 时 间 可 以 加 入 值 , 然 后 x 前 需 要 加 入 l − 1 个 值 , 即 需 选 择 l − 1 个 时 间 加 入 值 , 所 以 , 所 以 组 合 系 数 为 C i − 2 l − 1 , 我们先枚举一个x,保证x前的数是由x长出来的,即后面的方案数为pre[i-l][x-1],即后面的最大值不超过x,前面的可以随便选数,为dp[i-l][x]因为相当于我们已经有一个 x,0,的序列,长度为2,我们可以在0前面和x前面选数,即已经有2个时间填了数,所以总共有i-2个时间可以加入值,然后x前需要加入l-1个值,即需选择l-1个时间加入值,所以,所以组合系数为C_{i-2}^{l-1}, xxxpre[il][x1],x便dp[il][x]x020x2i2xl1l1Ci2l1

所以dp[i][j]=(dp[i][j]+dp[i-l][j]*pre[l][j-1]*C(i-2,l-1))

————————————————————————————————————— 初 始 状 态 : 将 d p [ 1 ] [ 0 , 1 , . . . . , k ] 都 赋 值 为 1 , 这 样 就 能 保 证 后 面 的 最 大 值 可 以 为 任 意 数 都 可 以 转 移 初始状态:将dp[1][0,1,....,k]都赋值为1,这样就能保证后面的最大值可以为任意数都可以转移 dp[1][0,1,....,k]1
—————————————————————————————————————

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;//有乘法,所以要开longlong
const int N=305;
ll n,k,mod,c[N][N],pre[N][N],dp[N][N];
int main(){
	scanf("%lld%lld%lld",&n,&k,&mod);
	c[1][0]=c[1][1]=1%mod;c[0][0]=1%mod;
	for(int i=2;i<=n;i++){
		c[i][i]=1%mod;c[i][0]=1%mod;
		for(int j=1;j<i;j++)
		{
			c[i][j]=1ll*(c[i-1][j-1]+c[i-1][j])%mod;
		}
	}
	dp[1][0]=1%mod;pre[1][0]=1%mod;
    for(int i=1;i<=k;i++){dp[1][i]=1%mod;pre[1][i]=(pre[1][i-1]+dp[1][i])%mod;}
	for(int i=2;i<=n+1;i++)                       
	   for(int j=1;j<=k;j++){
		for(int len=1;len<i;len++){
		  dp[i][j]=1ll*(dp[i][j]+(((dp[i-len][j])*c[i-2][len-1]%mod)*(pre[len][j-1])%mod)%mod)%mod;
		  pre[i][j]=1ll*((pre[i][j-1]+dp[i][j])%mod)%mod;
	     }
	}
	printf("%lld",dp[n+1][k]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值