Newcoder 139 B.Symmetric Matrix(dp+组合数学)

本文探讨了求解特定条件下n×n矩阵数量的问题,条件包括矩阵元素的取值范围、矩阵的对称性、行和限制及对角线元素的固定值。通过将问题转化为求解特定无向图的数量,提出了使用动态规划的方法进行高效计算。

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

Description

求满足下列条件的n×nn×n矩阵的个数:

1.Ai,j{0,1,2},1i,jnAi,j∈{0,1,2},1≤i,j≤n

2.Ai,j=Aj,i,1i,jnAi,j=Aj,i,1≤i,j≤n

3.Ai,1+Ai,2+...+Ai,n=2,1inAi,1+Ai,2+...+Ai,n=2,1≤i≤n

4.A1,1=A2,2=...=An,n=0A1,1=A2,2=...=An,n=0

Input

多组用例,每组用例输入两个整数n,m(1n105,1m109,n107)n,m(1≤n≤105,1≤m≤109,∑n≤107)

Output

输出满足条件的矩阵个数,结果模mm

Sample Input

3 1000000000
100000 1000000000

Sample Output

1
507109376

Solution

将该矩阵看作一无向图的邻接矩阵,则问题等价于求n个节点、无自环、每点度数为22的无向图个数。一条无向边产生两个度,故该图只有n条边,加之每点无自环且度数为22,故该图必然由若干简单环组成。令dp(n)表示nn个节点的满足条件的图的个数,考虑第n个节点所处环的大小,如果第nn个点在一个长度为2环中,那么方案数为(n1)dp(n2)(n−1)dp(n−2),如果第nn个点在一个长度为k+1的环(k2)(k≥2),从n1n−1个点中选出kk个点的排列数为An1k=(n1)!(n1k)!,由于选出的kk个点和第n个点组成环,故顺时针和逆时针方向等价,进而有转移

dp(n)=(n1)dp(n2)+k=2n1(n1)!2(n1k)!dp(n1k)=(n1)dp(n2)+k=0n3(n1)!2k!dp(k)dp(n)=(n−1)dp(n−2)+∑k=2n−1(n−1)!2(n−1−k)!dp(n−1−k)=(n−1)dp(n−2)+∑k=0n−3(n−1)!2k!dp(k)

g(n)=k=0n3(n1)!2k!dp(k)g(n)=∑k=0n−3(n−1)!2k!dp(k),进而有g(n)=(n1)g(n1)+(n1)(n2)2dp(n3)g(n)=(n−1)g(n−1)+(n−1)(n−2)2dp(n−3)

考虑到(n1)dp(n1)=(n1)(n2)dp(n3)+(n1)g(n1)(n−1)dp(n−1)=(n−1)(n−2)dp(n−3)+(n−1)g(n−1),故有以下递推式

dp(n)=(n1)(dp(n1)+dp(n2))(n1)(n2)2dp(n3)dp(n)=(n−1)(dp(n−1)+dp(n−2))−(n−1)(n−2)2dp(n−3)O(n)O(n)预处理即可O(1)O(1)查询

Code

#include<cstdio>
using namespace std;
typedef long long ll;
int n,m,dp[100005];
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        dp[1]=0;dp[2]=dp[3]=1%m;
        for(int i=4;i<=n;i++)
        {
            int t1=(ll)(i-1)*(dp[i-1]+dp[i-2])%m;
            int t2=(ll)(i-1)*(i-2)/2%m*dp[i-3]%m;
            dp[i]=(t1-t2+m)%m;
        }
        printf("%d\n",dp[n]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值