牛客网多校1 Symmetric Matrix(递推)

题目:构造一个n*n的矩阵,使得Ai,i = 0,Ai,j = Aj,i,Ai,1+Ai,2+...+Ai,n = 2。求种类数。

题解:

  把构造的矩阵当成邻接矩阵考虑。那么所有点的度数都为2,且存在重边但不存在自环。这种情况的图为多个环,即每个点都在且仅在一个环里。考虑每次加一个点来递推dp[]。假设当前是第n个点,从前n-1个点中筛出(1~n-3)个点和第n个点形成环。设n-1个点中保留k个点,即筛出n-1-k个点和第n个点形成环。

递推方程为:f(n) = (n-1)f(n-2)+sigma(k:2->n-3)C(n-1,k)f(k)(n-1-k)!/2;

  其中(n-1)f(n-2)为从n-1个点中筛出1个点的情况。C(n-1,k)为从n-1个点中筛出k个点的组合数(k表示保留的个数)。(n-1-k)!表示筛出的n-1-k个数与第n个数一共n-k个数构成环的种数。

  /2是因为去掉像1 2 3 4 和 1 4 3 2这种对称的情况。但是当k=1时就不用/2所以就把k=1的情况先写出来。

然后就是化简递推方程:

                    C(n-1,k)f(k)(n-1-k)!/2 = f(k)(n-1)!/k!/2

                    f(n) = (n-1)f(n-2)+sigma(k:2->n-3)f(k)(n-1)!/k!/2

         (n-1)f(n-1) = (n-1)(n-2)f(n-3)+sigma(k:2->n-4)f(k)(n-1)!/k!/2

减一下就变成:f(n) = (n-1)f(n-1)+(n-1)f(n-2)-(n-1)(n-2)f(n-3)/2

#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int n;
ll m,dp[maxn];
int main()
{
    dp[1]=0;dp[2]=1;dp[3]=1;
    while(~scanf("%d%lld",&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)/2ll*dp[i-3]%m+m)%m;
        printf("%lld\n",dp[n]);
    }
    return 0;
}

 

你可能感兴趣的:(dp,多校,递推)