CF2219D Token Removing(DP,计数)
题意:
对长度为 \(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)\). 转移方程:
#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;
}

浙公网安备 33010602011771号