B
World Fragments I
https://ac.nowcoder.com/acm/contest/57357/A
将的数看作,将的数看作,则任何,或者都是合法的,只有或者有可能会不合法,设表示考虑了前个,第个为时,共用了个的合法方案数,转移方程考虑枚举往前是一连串的或者,枚举从哪里转移而来,若由转移而来,那么在这个区间全是或者,考虑合法方案这一段的填的数(从剩余的数中取这个区间长度的数出来)大小是固定的即从大到小或者从小到大放置,考虑到位置才不合法,则这一段数除了最小/最大的不能放在(否则就合法),其它的都可以,然后令剩下的数按照合法顺序放即可,最后后面可以随便放,于是不合法方案就可以算出来了
code
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 605;
int T, n, n2, m;
int fac[maxn];
int c[maxn][maxn];
int f[maxn][maxn][2];
void init ()
{
fac[0] = c[0][0] = 1;
for (int i = 1; i <= n2; ++i) fac[i] = 1ll * fac[i - 1] * i % m;
for (int i = 1; i <= n2; ++i) {
c[i][0] = 1;
for (int j = 1; j <= i; ++j)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % m;
}
for (int i = 1; i <= n2; ++i)
for (int j = 0; j <= n2; ++j) f[i][j][0] = f[i][j][1] = 0;
}
int main ()
{
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
n2 = n << 1;
init();
f[0][0][0] = f[0][0][1] = 1;
int ans = 0;
for (int i = 1; i <= n2; ++i) {
for (int j = min(i, n); j >= 0; --j) {
for (int k = i - 1; k >= 0; --k) {
int t0 = j - (i - k);
if (t0 < 0 || t0 > min(k, n)) continue;
f[i][j][0] += 1ll * f[k][t0][1] * c[n - t0][i - k] % m;
f[i][j][0] %= m;
ans += 1ll * f[k][t0][1] * c[n - t0][i - k] % m * (i - k - 1) % m * i % m * fac[n2 - i] % m;
ans %= m;
}
for (int k = i - 1; k >= 0; --k) {
int t1 = (i - j) - (i - k);
if (t1 < 0 || t1 > min(n, k)) continue;
f[i][j][1] += 1ll * f[k][j][0] * c[n - t1][i - k] % m;
f[i][j][1] %= m;
ans += 1ll * f[k][j][0] * c[n - t1][i - k] % m * (i - k - 1) % m * i % m * fac[n2 - i] % m;
ans %= m;
}
}
}
ans += (1ll * f[n2][n][0] * n2 % m + 1ll * f[n2][n][1] * n2 % m) % m;
ans %= m;
printf("%d\n", ans);
}
return 0;
}