Codeforces 1439D - INOI Final Contests(DP)
首先考虑 \(n=m\) 的情况,根据经典接链成环的模型,假设 \(dp1_i\) 表示 \(i\) 个人 \(i\) 个空位的方案数,那么可以得到 \(dp1_i=(i+1)^{i-1}·2^i\),具体方法就是添加一个 \(i+1\) 号位成为一个环,如果不会可以看那题题解,这里不赘述。
但是这题 \(n\ne m\) 显然没有那么多的性质,因此我们考虑如何用相对递推的方法求解这个 \(dp1_i\),稍微想想可以得到:
稍微解释一下这个式子。我们枚举最后一个到达的人的位置,假设为 \(j\)。那么最后一个人恰有 \(i+1\) 种选择:\((L,1),(L,2),\cdots (L,j),(R,j),(R,j+1),\cdots,(R,i)\),共有 \(i+1\) 种选择,因此式子里有个系数 \(i+1\)。而左右两边又分别是一个独立的问题——显然左边的点的 \(a\) 不可能在右边,右边的点的 \(a\) 不可能在左边,因此方案数可以直接用两边的 \(dp1\) 乘起来,再乘上从 \(i-1\) 个人中选 \(j-1\) 个人放在左边的方案数 \(\dbinom{i-1}{j-1}\) 得到。
但是题目所求并不是方案数,因此我们再考虑 \(dp2_i\) 表示对于所有 \(i\) 个人 \(i\) 个空位的方案,计算它们移动的距离之和。仿照 \(dp1\) 的转移方法同样可以得到
这样我们就解决了 \(n=m\) 的情况。接下来考虑 \(n\ne m\) 的情况。
我们设 \(dp3_{i,j},dp4_{i,j}\) 分别表示 \(n=i,m=j\) 的方案数、距离之和,显然 \(i=j\) 或 \(j=0\) 时方案数易求,考虑如何转移。我们枚举最后一段连续的被占用的座位长度 \(l\),那么有
直接转移即可。时间复杂度 \(n^3\)。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500;
int n, m, mod, dp1[MAXN + 5], dp2[MAXN + 5], c[MAXN + 5][MAXN + 5], dp3[MAXN + 5][MAXN + 5], dp4[MAXN + 5][MAXN + 5];
int main() {
scanf("%d%d%d", &n, &m, &mod);
for (int i = 0; i <= n; i++) {
c[i][0] = 1;
for (int j = 1; j <= i; j++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
dp1[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp1[i] = (dp1[i] + 1ll * dp1[j - 1] * dp1[i - j] % mod * c[i - 1][j - 1] % mod * (i + 1)) % mod;
dp2[i] = (dp2[i] + 1ll * (1ll * dp1[j - 1] * dp1[i - j] % mod * (c[j][2] + c[i - j + 1][2]) % mod + 1ll * dp2[j - 1] * dp1[i - j] % mod * (i + 1) % mod
+ 1ll * dp1[j - 1] * dp2[i - j] % mod * (i + 1) % mod) % mod * c[i - 1][j - 1]) % mod;
}
}
for (int i = 0; i <= n; i++) {
dp3[i][0] = 1; dp3[i][i] = dp1[i]; dp4[i][i] = dp2[i];
for (int j = 1; j < i; j++) for (int l = 0; l <= min(j, i - 1); l++) {
dp3[i][j] = (dp3[i][j] + 1ll * c[j][l] * dp3[i - l - 1][j - l] % mod * dp1[l]) % mod;
dp4[i][j] = (dp4[i][j] + 1ll * (1ll * dp3[i - l - 1][j - l] * dp2[l] + 1ll * dp4[i - l - 1][j - l] * dp1[l]) % mod * c[j][l]) % mod;
}
}
printf("%d\n", dp4[n][m]);
}