链接:https://ac.nowcoder.com/acm/problem/17134
solution
首先看一下
n
×
n
n \times n
n × n 的方阵需要满足的条件:
矩阵中的任意元素
a
i
,
j
∈
{
0
,
1
,
2
}
a_{i,j} \in \{0,1,2\}
a i , j ∈ { 0 , 1 , 2 }
满足对称矩阵
每行的和是2
主对角线都是0
这些条件加起来就是无向图的邻接矩阵表示,
a
i
,
j
a_{i,j}
a i , j 就是点
i
i
i 到点
j
j
j 的权值,我们把这个权值定义为边的个数,即点
i
i
i 到点
j
j
j 的边的个数,这就是数形结合 的思想。 转化成图以后我们发现,主对角线都是0,说明这个图没有自环;每行的和都是2,也就是每个点的度都是2,这就意味着这个图是由若干个环组成的 ,且没有自环,环之间没有公共部分。 我们考虑递推
d
p
x
dp_{x}
d p x 表示
x
x
x 个点可以组成若干环的不同方案数,那么显然
d
p
1
=
0
,
d
p
2
=
1
,
d
p
3
=
1
dp_1=0,dp_2=1,dp_3=1
d p 1 = 0 , d p 2 = 1 , d p 3 = 1 ,然后我们再考虑转移,已经有
n
−
1
n-1
n − 1 个点时再加入第
n
n
n 个点:
加入的第
n
n
n 个点与
n
−
1
n-1
n − 1 个点中的一个构成一个二元环,这个点可以有
n
−
1
n-1
n − 1 种选择,然后剩下的
n
−
2
n-2
n − 2 个点有
d
p
n
−
2
dp_{n-2}
d p n − 2 种不同的方案,所以方案数为
(
n
−
1
)
×
d
p
n
−
2
(n-1)\times dp_{n-2}
( n − 1 ) × d p n − 2 。
加入的第
n
n
n 个点与之前的
k
−
1
k-1
k − 1 个点构成一个
k
k
k 元环(
k
≥
3
k\geq 3
k ≥ 3 ,因为二元环上面已经讨论过了),选择前面的
k
−
1
k-1
k − 1 个点共有
C
n
−
1
k
−
1
C_{n-1}^{k-1}
C n − 1 k − 1 中方法,这个
k
k
k 元环的圆排列 一共有
(
k
−
1
)
!
2
\frac{(k-1)!}{2}
2 ( k − 1 ) ! ,剩下的
n
−
k
n-k
n − k 个点有
d
p
n
−
k
dp_{n-k}
d p n − k 种方案,所以方案数是
∑
k
=
3
n
(
C
n
−
1
k
−
1
×
(
k
−
1
)
!
2
×
d
p
n
−
k
)
\sum_{k=3}^{n} (C_{n-1}^{k-1}\times\frac{(k-1)!}{2}\times dp_{n-k})
∑ k = 3 n ( C n − 1 k − 1 × 2 ( k − 1 ) ! × d p n − k ) 。
所以最后的状态转移方程就可以写成
d
p
n
=
(
n
−
1
)
×
d
p
n
−
2
+
∑
k
=
3
n
(
C
n
−
1
k
−
1
×
(
k
−
1
)
!
2
×
d
p
n
−
k
)
dp_{n}=(n-1)\times dp_{n-2}+\sum_{k=3}^{n} (C_{n-1}^{k-1}\times\frac{(k-1)!}{2}\times dp_{n-k})
d p n = ( n − 1 ) × d p n − 2 + k = 3 ∑ n ( C n − 1 k − 1 × 2 ( k − 1 ) ! × d p n − k ) 然后我们需要处理这个方程:
d
p
n
=
(
n
−
1
)
×
d
p
n
−
2
+
∑
k
=
3
n
(
(
n
−
1
)
!
(
k
−
1
)
!
×
(
n
−
k
)
!
×
(
k
−
1
)
!
2
×
d
p
n
−
k
)
dp_{n}=(n-1)\times dp_{n-2}+\sum_{k=3}^{n} (\frac{(n-1)!}{(k-1) !\times (n-k)!} \times\frac{(k-1)!}{2}\times dp_{n-k})
d p n = ( n − 1 ) × d p n − 2 + k = 3 ∑ n ( ( k − 1 ) ! × ( n − k ) ! ( n − 1 ) ! × 2 ( k − 1 ) ! × d p n − k )
=
(
n
−
1
)
×
d
p
n
−
2
+
∑
k
=
3
n
(
(
n
−
1
)
!
(
n
−
k
)
!
×
2
×
d
p
n
−
k
)
=(n-1)\times dp_{n-2}+\sum_{k=3}^{n} (\frac{(n-1)!}{(n-k)!\times 2} \times dp_{n-k})
= ( n − 1 ) × d p n − 2 + k = 3 ∑ n ( ( n − k ) ! × 2 ( n − 1 ) ! × d p n − k ) 这里
k
k
k 表示第
n
n
n 个点所在的
k
k
k 元环,我们设
x
=
n
−
k
x=n-k
x = n − k ,
(
3
≤
k
≤
n
)
(3\le k\le n)
( 3 ≤ k ≤ n ) ,那么
x
x
x 就表示其他的点
=
(
n
−
1
)
×
d
p
n
−
2
+
∑
x
=
0
n
−
3
(
(
n
−
1
)
!
x
!
×
2
×
d
p
x
)
=(n-1)\times dp_{n-2}+\sum_{x=0}^{n-3} (\frac{(n-1)!}{x!\times 2} \times dp_{x})
= ( n − 1 ) × d p n − 2 + x = 0 ∑ n − 3 ( x ! × 2 ( n − 1 ) ! × d p x )
d
p
n
−
1
=
(
n
−
2
)
×
d
p
n
−
3
+
∑
x
=
0
n
−
4
(
(
n
−
2
)
!
x
!
×
2
×
d
p
x
)
dp_{n-1}=(n-2)\times dp_{n-3}+\sum_{x=0}^{n-4} (\frac{(n-2)!}{x!\times 2} \times dp_{x})
d p n − 1 = ( n − 2 ) × d p n − 3 + x = 0 ∑ n − 4 ( x ! × 2 ( n − 2 ) ! × d p x ) 观察比较
d
p
n
dp_{n}
d p n 和
d
p
n
−
1
dp_{n-1}
d p n − 1 可以发现,两式的
∑
\sum
∑ 部分只相差一项,所以令
d
p
n
−
(
n
−
1
)
×
d
p
n
−
1
=
(
n
−
1
)
×
d
p
n
−
2
−
(
n
−
1
)
×
(
n
−
2
)
×
d
p
n
−
3
+
(
n
−
1
)
!
(
n
−
3
)
!
×
2
×
d
p
n
−
3
dp_{n}-(n-1)\times dp_{n-1}=(n-1)\times dp_{n-2}-(n-1)\times(n-2)\times dp_{n-3}+\frac{(n-1)!}{(n-3)!\times 2} \times dp_{n-3}
d p n − ( n − 1 ) × d p n − 1 = ( n − 1 ) × d p n − 2 − ( n − 1 ) × ( n − 2 ) × d p n − 3 + ( n − 3 ) ! × 2 ( n − 1 ) ! × d p n − 3 最后,移项得:
d
p
n
=
(
n
−
1
)
×
(
d
p
n
−
1
+
d
p
n
−
2
)
−
1
2
(
n
−
1
)
×
(
n
−
2
)
×
d
p
n
−
3
dp_{n}=(n-1)\times (dp_{n-1}+dp_{n-2})-\frac{1}{2}(n-1)\times(n-2)\times dp_{n-3}
d p n = ( n − 1 ) × ( d p n − 1 + d p n − 2 ) − 2 1 ( n − 1 ) × ( n − 2 ) × d p n − 3
注意减法取模和 long long 参考题解 【每日一题】4月29日题目精讲 dp+数学 、Symmetric Matrix
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5 ;
int dp[ N] ;
int main ( )
{
ios:: sync_with_stdio ( false ) , cin. tie ( nullptr ) , cout. tie ( nullptr ) ;
ll n, m;
dp[ 1 ] = 0 , dp[ 2 ] = 1 , dp[ 3 ] = 1 ;
while ( cin >> n >> m)
{
for ( int i = 4 ; i <= n; i++ )
dp[ i] = ( ( 1LL * ( i - 1 ) * ( dp[ i - 1 ] + dp[ i - 2 ] ) % m - 1LL * ( i - 1 ) * ( i - 2 ) / 2 * dp[ i - 3 ] % m) % m + m) % m;
cout << dp[ n] << endl;
}
return 0 ;
}