题意:
给定 NNN, 求有多少个大小为 N×NN \times NN×N 的矩阵 AAA,满足
Aii=0,∀i∈[1,N]0≤Aij=Aji≤2,∀i,j∈[1,N],i≠j∑j=1NAij=2,∀i∈[1,N]
A_{ii} = 0, \quad \forall i \in [1, N] \\
0 \le A_{ij} = A_{ji} \le 2, \quad \forall i, j \in [1, N], i \ne j\\
\sum_{j = 1}^{N} A_{ij} = 2, \quad \forall i \in [1, N]\\
Aii=0,∀i∈[1,N]0≤Aij=Aji≤2,∀i,j∈[1,N],i̸=jj=1∑NAij=2,∀i∈[1,N]
分析:
将矩阵视为 NNN 个点的图邻接矩阵,则题意转化为有多少种图满足节点度数都为2。可以有重边,但是不可以有自环。
计算过程:
记 f(n)f(n)f(n) 为 nnn 个点时应输出的结果。考虑在节点数为 n−1n-1n−1 个图上加一个点。如果点 nnn 构成了重边,则必只与 {1,2,…,n−1}\{1, 2, \dots, n-1\}{1,2,…,n−1} 中一个点相连,剩余 n−2n-2n−2 个点自己解决自己的问题,所以有 (n−1)f(n−2) (n-1) f(n-2)(n−1)f(n−2) 种情况。
如果没有构成重边,则点 nnn 连通的点数一定超过 222 个,所以从 n−1n-1n−1 个里选 k ( 2≤k≤n−1)k\ (\ 2\le k\le n-1)k ( 2≤k≤n−1) 个点与 nnn 相连,有 Cn−1kC_{n-1}^{k}Cn−1k 种。剩余 n−1−kn-1-kn−1−k 个点自己解决自己,有 f(n−1−k)f(n-1-k)f(n−1−k) 种,其中与 kkk 个点相连通时,考虑从环的断点加入新点, kkk 个点的链有 k!k!k! 种情况,围起来情况数少一半,因为这个链正着排和倒着排围起来是一样的。有 k!2\frac{k!}{2}2k! 种。所以一共有 ∑2≤k<n−2Cn−1kk!2f(n−1−k)=∑2≤k<n−2(n−1)!k!(n−1−k)!k!2f(n−1−k)\displaystyle\sum_{2\le k\lt n-2} C_{n-1}^k \frac{k!}{2} f(n-1-k) = \displaystyle\sum_{2\le k\lt n-2} \frac{(n-1)!}{k!(n-1-k)!} \frac{k!}{2} f(n-1-k)2≤k<n−2∑Cn−1k2k!f(n−1−k)=2≤k<n−2∑k!(n−1−k)!(n−1)!2k!f(n−1−k) 即 (n−1)!∑2≤k<n−2f(n−1−k)2(n−1−k)!\displaystyle(n-1)!\sum_{2\le k\lt n-2} \frac{f(n-1-k)}{2(n-1-k)!} (n−1)!2≤k<n−2∑2(n−1−k)!f(n−1−k) 种。则 f(n)=(n−1)f(n−2)+(n−1)!∑2≤k<n−2f(n−1−k)2(n−1−k)!f(n) = (n-1)f(n-2) + \displaystyle(n-1)!\sum_{2\le k\lt n-2} \frac{f(n-1-k)}{2(n-1-k)!}f(n)=(n−1)f(n−2)+(n−1)!2≤k<n−2∑2(n−1−k)!f(n−1−k)记 g(n)=(n−1)!∑2≤k<n−2f(n−1−k)2(n−1−k)!g(n) = \displaystyle(n-1)!\sum_{2\le k\lt n-2} \frac{f(n-1-k)}{2(n-1-k)!}g(n)=(n−1)!2≤k<n−2∑2(n−1−k)!f(n−1−k) 得到
g(n−1)=(n−2)!∑2≤p≤n−4f(p)2p!g(n-1) = (n-2)! \displaystyle\sum_{2\le p\le n-4} \frac{f(p)}{2p!}g(n−1)=(n−2)!2≤p≤n−4∑2p!f(p)
g(n)=(n−1)!∑2≤p≤n−3f(p)2p!g(n) = (n-1)! \displaystyle\sum_{2\le p\le n-3} \frac{f(p)}{2p!}g(n)=(n−1)!2≤p≤n−3∑2p!f(p)所以可以凑齐f()f()f()项后得出比例,即
g(n)=(n−1)[g(n−1)+(n−2)!f(n−3)2(n−3)!]g(n) = (n-1)[g(n-1) + (n-2)!\frac{f(n-3)}{2(n-3)!}]g(n)=(n−1)[g(n−1)+(n−2)!2(n−3)!f(n−3)]化简
g(n)=(n−1)g(n−1)+(n−1)(n−2)2f(n−3)g(n) = (n-1)g(n-1) + \frac{(n-1)(n-2)}{2}f(n-3)g(n)=(n−1)g(n−1)+2(n−1)(n−2)f(n−3)
至此得到了 g(n)g(n)g(n) 的线性递推式,同时也得出了 f(n)f(n)f(n) 的线性递推公式。所以问题解决。
代码
#include <bits/stdc++.h>
using namespace std;
const int N_MAX = 1e5 + 10;
long long f[N_MAX], g[N_MAX];
long long N, M;
int main() {
f[2] = f[3] = 1;
g[3] = 1;
while (~scanf("%lld%lld", &N, &M)) {
for (long long i = 4; i <= N; i++) {
g[i] = (i-1) * g[i-1] % M + ((i-1) * (i-2)/2) % M * f[i-3] % M;
g[i] %= M;
f[i] = (i-1) * f[i-2] % M + g[i] % M;
f[i] %= M;
}
printf("%lld\n", f[N]);
}
}