题解:P16351 「Gensokyo OI Round 1」秘神之钥

· · 题解

题目链接:「Gensokyo OI Round 1」秘神之钥

神秘计数题。

先考虑什么样的排列是不满足条件的。

手玩或者打表一下不难发现,第 i 次操作时的 p_i 一定是初始状态下的 a_1a_n,且 p_1p_n 永远相邻。

可以分类讨论一下:n 为奇数或偶数。

这个时候只要观察一下另外一个相邻数会是什么。当 n 为偶数时,可以发现和 p_1 相邻的会是所有的偶数位,而和 p_n 相邻的是所有的奇数位。接下来我们考虑怎么计算答案:

考虑 p_1<p_n 的情况,首先枚举一下 p_1 的值,设其为 i,则所有偶数位都需要 >i,但是因为 p_n 比较特殊,所以我们先钦定另外 \left(\frac{n}{2}-1\right) 个数 >i,这样的方案数为 A_{n-i}^{\frac{n}{2}-1}。剩下的数可以随便排列,但要注意 p_n 一定要是其中最大的,所以方案数为 \left(\frac{n}{2}-1\right)!

得到结果为:

\sum\limits_{i=1}^{n}A_{n-i}^{\frac{n}{2}-1}\left(\frac{n}{2}-1\right)!

但是这样会多算,要考虑最终 p_n<p_1 的情况,这种情况当且仅当 p_n=\frac{n}{2}p_{1}=\frac{n}{2}+1。剩下的奇数位都小于 p_{n},偶数位都大于 p_1,这部分方案数为 \left[\left(\frac{n}{2}-1\right)!\right]^2

最终方案数为:

\sum\limits_{i=1}^{n}A_{n-i}^{\frac{n}{2}-1}\left(\frac{n}{2}-1\right)!-\left[\left(\frac{n}{2}-1\right)!\right]^2 接下来考虑 $n$ 为奇数的情况。依旧手玩或打表不难发现,$p_1$ 会和所有的偶数位以及 $p_2$ 相邻,$p_n$ 回合所有的奇数位以及 $p_3$ 相邻。 考虑 $p_1<p_n$ 的情况,$p_1<p_2,p_3<p_n$,首先 $p_2$ 和 $p_3$ 的位置可以分出先后,方案数为 $2$。接下来可以看作剩余的偶数位不能 $<a_1$,剩余的奇数位不能 $>a_n$ 的方案数。这个可以枚举一下有多少个偶数位 $<a_n$,设其有 $i$ 个。选择数字的方式有 $\binom{\frac{n-1}{2}-1}{i}$,接下来可以看作每次往空位中插入一个数字,方案数为 $3^{\overline{i}}$,剩下的 $\left(\frac{n-1}{2}-1-i\right)$ 个数可以随便排,方案数为 $\left(\frac{n-1}{2}-1-i\right)!$。接下来奇数位上的数也可以理解为插空位,方案数为 $\left(4+i\right)^{\overline{\frac{n-1}{2}-2}}$。 因此最终答案为: $$2\sum\limits_{i=0}^{\frac{n-1}{2}-1}3^{\overline{i}}\binom{\frac{n-1}{2}-1}{i}\left(\frac{n-1}{2}-1-i\right)!\left(4+i\right)^{\overline{\frac{n-1}{2}-2}}$$ 对于 $p_1>p_n$ 的情况,答案是一样的,乘 $2$ 即可。 代码: ```cpp #include <bits/stdc++.h> #define int long long using namespace std; int T, n, mod, ans, fac[1000005], inv[1000005], facinv[1000005]; int A(int x, int y) { if (y > x) return 0; return fac[x] * facinv[x - y] % mod; } int C(int x, int y) { return (fac[x] * facinv[x - y] % mod) * facinv[y] % mod; } signed main() { fac[0] = 1; cin >> T; while (T--) { ans = 0; cin >> n >> mod; for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % mod; inv[0] = 0; inv[1] = 1; for(int i = 2; i <= n; ++ i) inv[i] = (mod - mod / i) * inv[mod % i] % mod; facinv[0] = 1; for (int i = 1; i <= n; i++) facinv[i] = facinv[i - 1] * inv[i] % mod; if (n == 3) { cout << 4 << endl; continue; } if (n % 2 == 0) { for (int i = 1; i <= n; i++) { ans = (ans + A(n - i, n / 2 - 1) * fac[n / 2 - 1]) % mod; } cout << (fac[n] - (ans - fac[n / 2 - 1] * fac[n / 2 - 1] % mod) * 2 % mod + mod) % mod << endl; } else { for (int i = 0; i <= n / 2 - 1; i++) { ans = (ans + ((A(3 + i - 1, i) * C(n / 2 - 1, i) % mod) * fac[n / 2 - 1 - i] % mod) * A(4 + i + n / 2 - 3, n / 2 - 2) % mod) % mod; } cout << (fac[n] - 4 * ans % mod + mod) % mod << endl; } } return 0; } ```