[牛客139B-Symmetric Matrix]

这篇博客探讨了如何计算满足特定条件的N×N矩阵的数量,其中矩阵元素的限制和节点度数的约束转化为图论问题。通过建立递推公式,解析了矩阵对称性的计算过程,并提供了相关代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

给定 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]0Aij=Aji2,i,j[1,N],i̸=jj=1NAij=2,i[1,N]

分析:

将矩阵视为 NNN 个点的图邻接矩阵,则题意转化为有多少种图满足节点度数都为2。可以有重边,但是不可以有自环。

计算过程:

f(n)f(n)f(n)nnn 个点时应输出的结果。考虑在节点数为 n−1n-1n1 个图上加一个点。如果点 nnn 构成了重边,则必只与 {1,2,…,n−1}\{1, 2, \dots, n-1\}{1,2,,n1} 中一个点相连,剩余 n−2n-2n2 个点自己解决自己的问题,所以有 (n−1)f(n−2) (n-1) f(n-2)(n1)f(n2) 种情况。
如果没有构成重边,则点 nnn 连通的点数一定超过 222 个,所以从 n−1n-1n1 个里选 k ( 2≤k≤n−1)k\ (\ 2\le k\le n-1)k ( 2kn1) 个点与 nnn 相连,有 Cn−1kC_{n-1}^{k}Cn1k 种。剩余 n−1−kn-1-kn1k 个点自己解决自己,有 f(n−1−k)f(n-1-k)f(n1k) 种,其中与 kkk 个点相连通时,考虑从环的断点加入新点, kkk 个点的链有 k!k!k! 种情况,围起来情况数少一半,因为这个链正着排和倒着排围起来是一样的。有 k!2\frac{k!}{2}2k! 种。所以一共有 ∑2≤k&lt;n−2Cn−1kk!2f(n−1−k)=∑2≤k&lt;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)2k<n2Cn1k2k!f(n1k)=2k<n2k!(n1k)!(n1)!2k!f(n1k)(n−1)!∑2≤k&lt;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)!} (n1)!2k<n22(n1k)!f(n1k) 种。则 f(n)=(n−1)f(n−2)+(n−1)!∑2≤k&lt;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)=(n1)f(n2)+(n1)!2k<n22(n1k)!f(n1k)g(n)=(n−1)!∑2≤k&lt;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)=(n1)!2k<n22(n1k)!f(n1k) 得到
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(n1)=(n2)!2pn42p!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)=(n1)!2pn32p!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)=(n1)[g(n1)+(n2)!2(n3)!f(n3)]化简
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)=(n1)g(n1)+2(n1)(n2)f(n3)
至此得到了 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]);
  }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值