题意:
给定
N
N
N, 求有多少个大小为
N
×
N
N \times N
N×N 的矩阵
A
A
A,满足
A
i
i
=
0
,
∀
i
∈
[
1
,
N
]
0
≤
A
i
j
=
A
j
i
≤
2
,
∀
i
,
j
∈
[
1
,
N
]
,
i
≠
j
∑
j
=
1
N
A
i
j
=
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]
分析:
将矩阵视为 N N N 个点的图邻接矩阵,则题意转化为有多少种图满足节点度数都为2。可以有重边,但是不可以有自环。
计算过程:
记
f
(
n
)
f(n)
f(n) 为
n
n
n 个点时应输出的结果。考虑在节点数为
n
−
1
n-1
n−1 个图上加一个点。如果点
n
n
n 构成了重边,则必只与
{
1
,
2
,
…
,
n
−
1
}
\{1, 2, \dots, n-1\}
{1,2,…,n−1} 中一个点相连,剩余
n
−
2
n-2
n−2 个点自己解决自己的问题,所以有
(
n
−
1
)
f
(
n
−
2
)
(n-1) f(n-2)
(n−1)f(n−2) 种情况。
如果没有构成重边,则点
n
n
n 连通的点数一定超过
2
2
2 个,所以从
n
−
1
n-1
n−1 个里选
k
(
2
≤
k
≤
n
−
1
)
k\ (\ 2\le k\le n-1)
k ( 2≤k≤n−1) 个点与
n
n
n 相连,有
C
n
−
1
k
C_{n-1}^{k}
Cn−1k 种。剩余
n
−
1
−
k
n-1-k
n−1−k 个点自己解决自己,有
f
(
n
−
1
−
k
)
f(n-1-k)
f(n−1−k) 种,其中与
k
k
k 个点相连通时,考虑从环的断点加入新点,
k
k
k 个点的链有
k
!
k!
k! 种情况,围起来情况数少一半,因为这个链正着排和倒着排围起来是一样的。有
k
!
2
\frac{k!}{2}
2k! 种。所以一共有
∑
2
≤
k
<
n
−
2
C
n
−
1
k
k
!
2
f
(
n
−
1
−
k
)
=
∑
2
≤
k
<
n
−
2
(
n
−
1
)
!
k
!
(
n
−
1
−
k
)
!
k
!
2
f
(
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
−
2
f
(
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
−
2
f
(
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
−
2
f
(
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
−
4
f
(
p
)
2
p
!
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
−
3
f
(
p
)
2
p
!
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
)
2
f
(
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]);
}
}