CF2219D Token Removing(DP,计数)

CF2219D Token Removing

题意:
对长度为 \(n\) 的一个序列 \(\{a\}\),满足 \(0\le a_i\le i\).
\(a_i\ne 0\),则从闭区间 \([a_i,i]\) 中选择一个未被选择过的位置 \(t_i\);
\(a_i=0\),则不作任何操作.
\(f(a)\) 表示该序列 \(a\) 的操作方案数. 两方案不同当且仅当存在 \(i\),使得 \(t_i\ne t_i'\)

给定 \(n\),求长度为 \(n\) 的所有满足条件的序列 \(a\)\(f(a)\) 之和.


感觉题意十分抽象,可以翻译得具象一点.

给定 \(n\),求大小不大于 \(n\) 的三元组 \(\{(a_i,t_i,i)\}\) 的数量,其中 \(1\le a_i\le t_i\le i \le n\)\(t_i\) 两两不同,\(i\) 两两不同. \(n\le 5000\)

可以考虑,确定 \(a_i\) 选法的情况下 \(t_i\) 的选择方案数,或者确定 \(t_i\) 选法的情况下 \(a_i\) 的选择方案数.

如果我们考虑 \(a_i\) 的选法,确定了一系列区间 \([a_i,i]\),因为在任一个之前的 \(t_j\) 是否在区间 \([a_i,i]\) 内是不确定的,所以会比较难以计算 \(t\) 的选法. 从后往前考虑区间 \([a_i,i]\),任一个之后的 \(t_k\) 是否在区间 \([a_i,i]\) 内也是不确定的,同样难以计算 \(t\) 的选法.

如果我们确定了 \(t_i\) 的选法,那么 \(a\) 的选法为 \(\prod t_i\) .

\(f(i,j)\) 表示当前考虑到 \(i\),当前选的 \(t\)\(j\) 个的所有选择方案的 \(\prod t\) 总和.
考虑从 \(f(i-1,j-1)\) 转移过来时,把 \(i\) 加入 \(t\) 的集合里,但是这个 \(t=i\) 能和多少个未被匹配过的区间右端点匹配是难以计算的,因为前面的 \(t=k\) 匹配的是 \(i\) 之前还是 \(i\) 之后的右端点是未知的.

\(f(i,j)\) 表示当前从 \(n\) 考虑到 \(i\),当前选的 \(t\)\(j\) 个的所有选择方案的 \(\prod t\) 总和.
\(f(i+1,j-1)\) 转移过来时,把 \(i\) 加入 \(t\) 的集合里. 由于后面的 \(t=k\) 匹配的右端点一定在 \(i\) 之后,可知 \(t=i\) 能匹配的右端点的个数为 \((n-i+1)-(j-1)\). 转移方程:

\[f(i,j)=f(i+1,j)+f(i+1,j-1)\times i \times [(n-i+1)-(j-1)] \]

#define ll long long
#define MAXN 5007
ll f[MAXN][MAXN];
ll mod=1ll;
int n;
void R()
{
	scanf("%d%lld",&n,&mod);
	for (int i=0;i<=n+1;i++)
		for (int j=0;j<=n+1;j++)
			f[i][j]=0;
	f[n+1][0]=1;
	for (int i=n;i>=1;i--)
	{
		for (int j=0;j<=n-i+1;j++)
		{
			f[i][j]=f[i+1][j];
			if (j>0)
			{
				f[i][j]=(f[i][j]+f[i+1][j-1]*i%mod*(n-i-j+2)%mod)%mod;
			}
		}
	}
	ll ans=0;
	for (int j=0;j<=n;j++) ans=(ans+f[1][j])%mod;
	printf("%lld\n",ans);
	return;
}
posted @ 2025-07-06 15:33  Akuto_urusu  阅读(124)  评论(2)    收藏  举报