[AGC024E] Sequence Growing Hard

LXXX.[AGC024E] Sequence Growing Hard

首先,我们肯定能想到从第一个序列开始,依次加入一个新数得到下一个序列,同时还要保证字典序递增。我们如果让新数递增的话,就可以DP了。

我们首先观察往一个序列中加入一个不大于最大值的数会有多少种可能:

我们在1323中加入一个3

位置 结果
开头 31323
第一个数后 13323
第二个数后 13323
第三个数后 13233
第四个数后 13233

明显所有结果全都符合要求,但是有重复计算的地方。

我们可以强制要求加数必须加在连续一段相同的数的后面,在上例中就是你无法在第一个、第三个数后面添加3

我们可以设f[i][j][k]表示当前处理完成了前i个串,计划往第i+1个串里加入一个数j,并且有k个位置可以加入j的方案数。

f[i][j][k]可以转移到:

  1. 如果k>0,可以转移到f[i][j][k1],它的意义是我们跳过第k个位置不加。

  2. 如果k=0,可以转移到f[i][j+1][i],它的意义是第j个数已经全部加完,可以尝试j+1了。它有i个位置可以填,因为没有任何一个数与j+1相同,它可以直接加到任何数后面。

  3. 无论何时,都可以转移到f[i+1][j][k],意义是我们在第k个位置加入一个数。这共有k+1种加法,因为我们还有一种在开头的加法是一直可以的。

复杂度O(n3)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,p,f[310][310][310];
//f[i][j][k]:we've finished constructing the first i sequences, now we're going to add the number j into the i+1-th sqeuence, and there're k places to add j into
int main(){
	scanf("%d%d%d",&n,&m,&p),f[0][1][0]=1;
	for(int i=0;i<=n;i++)for(int j=1;j<=m;j++)for(int k=i;k>=0;k--){
		if(k)(f[i][j][k-1]+=f[i][j][k])%=p;//we decide not to add j to the k-th place, so we could add it to the (k-1)-th place.
		else(f[i][j+1][i]+=f[i][j][k])%=p;//we have tried every place j could be added to, now it's time to try j+1, which could be added into any place
		(f[i+1][j][k]+=1ll*f[i][j][k]*(k+1)%p)%=p;//we decide to add j to the k-th place, and there are (k+1) places for us to add (including the last one)
	}
	printf("%d\n",f[n][m+1][n]);//all n sequences've been constructed, and all number've been tried
	return 0;
}
posted @   Troverld  阅读(74)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示