Description
求满足下列条件的n×nn×n矩阵的个数:
1.Ai,j∈{0,1,2},1≤i,j≤nAi,j∈{0,1,2},1≤i,j≤n
2.Ai,j=Aj,i,1≤i,j≤nAi,j=Aj,i,1≤i,j≤n
3.Ai,1+Ai,2+...+Ai,n=2,1≤i≤nAi,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(1≤n≤105,1≤m≤109,∑n≤107)n,m(1≤n≤105,1≤m≤109,∑n≤107)
Output
输出满足条件的矩阵个数,结果模mm
Sample Input
3 1000000000
100000 1000000000
Sample Output
1
507109376
Solution
将该矩阵看作一无向图的邻接矩阵,则问题等价于求个节点、无自环、每点度数为22的无向图个数。一条无向边产生两个度,故该图只有条边,加之每点无自环且度数为22,故该图必然由若干简单环组成。令表示nn个节点的满足条件的图的个数,考虑第个节点所处环的大小,如果第nn个点在一个长度为环中,那么方案数为(n−1)dp(n−2)(n−1)dp(n−2),如果第nn个点在一个长度为的环(k≥2)(k≥2),从n−1n−1个点中选出kk个点的排列数为,由于选出的kk个点和第个点组成环,故顺时针和逆时针方向等价,进而有转移
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)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=0n−3(n−1)!2k!dp(k)g(n)=∑k=0n−3(n−1)!2k!dp(k),进而有g(n)=(n−1)g(n−1)+(n−1)(n−2)2dp(n−3)g(n)=(n−1)g(n−1)+(n−1)(n−2)2dp(n−3)
考虑到(n−1)dp(n−1)=(n−1)(n−2)dp(n−3)+(n−1)g(n−1)(n−1)dp(n−1)=(n−1)(n−2)dp(n−3)+(n−1)g(n−1),故有以下递推式
dp(n)=(n−1)(dp(n−1)+dp(n−2))−(n−1)(n−2)2dp(n−3)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]);
}
}