欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

NC17134 Symmetric Matrix(dp+数学)

程序员文章站 2024-02-21 18:55:34
...

NC17134 Symmetric Matrix(dp+数学)
链接:https://ac.nowcoder.com/acm/problem/17134

solution

首先看一下 n×nn \times n 的方阵需要满足的条件:

  1. 矩阵中的任意元素 ai,j{0,1,2}a_{i,j} \in \{0,1,2\}
  2. 满足对称矩阵
  3. 每行的和是2
  4. 主对角线都是0

这些条件加起来就是无向图的邻接矩阵表示,ai,ja_{i,j} 就是点 ii 到点 jj 的权值,我们把这个权值定义为边的个数,即点 ii 到点 jj 的边的个数,这就是数形结合的思想。
转化成图以后我们发现,主对角线都是0,说明这个图没有自环;每行的和都是2,也就是每个点的度都是2,这就意味着这个图是由若干个环组成的,且没有自环,环之间没有公共部分。
我们考虑递推 dpxdp_{x} 表示 xx 个点可以组成若干环的不同方案数,那么显然 dp1=0,dp2=1,dp3=1dp_1=0,dp_2=1,dp_3=1,然后我们再考虑转移,已经有 n1n-1 个点时再加入第 nn 个点:

  • 加入的第 nn 个点与 n1n-1 个点中的一个构成一个二元环,这个点可以有 n1n-1 种选择,然后剩下的 n2n-2 个点有 dpn2dp_{n-2} 种不同的方案,所以方案数为 (n1)×dpn2(n-1)\times dp_{n-2}
  • 加入的第 nn 个点与之前的 k1k-1 个点构成一个 kk 元环(k3k\geq 3,因为二元环上面已经讨论过了),选择前面的 k1k-1 个点共有 Cn1k1C_{n-1}^{k-1} 中方法,这个 kk 元环的圆排列一共有 (k1)!2\frac{(k-1)!}{2},剩下的 nkn-k 个点有 dpnkdp_{n-k} 种方案,所以方案数是 k=3n(Cn1k1×(k1)!2×dpnk)\sum_{k=3}^{n} (C_{n-1}^{k-1}\times\frac{(k-1)!}{2}\times dp_{n-k})

所以最后的状态转移方程就可以写成 dpn=(n1)×dpn2+k=3n(Cn1k1×(k1)!2×dpnk)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}) 然后我们需要处理这个方程:
dpn=(n1)×dpn2+k=3n((n1)!(k1)!×(nk)!×(k1)!2×dpnk) 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}) =(n1)×dpn2+k=3n((n1)!(nk)!×2×dpnk) =(n-1)\times dp_{n-2}+\sum_{k=3}^{n} (\frac{(n-1)!}{(n-k)!\times 2} \times dp_{n-k}) 这里 kk 表示第 nn 个点所在的 kk 元环,我们设 x=nkx=n-k(3kn)(3\le k\le n) ,那么 xx 就表示其他的点 =(n1)×dpn2+x=0n3((n1)!x!×2×dpx) =(n-1)\times dp_{n-2}+\sum_{x=0}^{n-3} (\frac{(n-1)!}{x!\times 2} \times dp_{x}) dpn1=(n2)×dpn3+x=0n4((n2)!x!×2×dpx) dp_{n-1}=(n-2)\times dp_{n-3}+\sum_{x=0}^{n-4} (\frac{(n-2)!}{x!\times 2} \times dp_{x})
观察比较 dpndp_{n}dpn1dp_{n-1} 可以发现,两式的 \sum 部分只相差一项,所以令
dpn(n1)×dpn1=(n1)×dpn2(n1)×(n2)×dpn3+(n1)!(n3)!×2×dpn3 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} 最后,移项得:
dpn=(n1)×(dpn1+dpn2)12(n1)×(n2)×dpn3dp_{n}=(n-1)\times (dp_{n-1}+dp_{n-2})-\frac{1}{2}(n-1)\times(n-2)\times dp_{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;
}