题意
给出一个矩阵,矩阵每行的和必须为2,且是一个主对称矩阵。问你大小为n的这样的合法矩阵有多少个。
分析
作者:美食不可负064
链接:https://www.nowcoder.com/discuss/87226?type=101&order=0&pos=1&page=1
来源:牛客网
题目给出的合法矩阵是一个类似与邻接矩阵的样式。 所以应该往这方面去考虑。
每行之和等于2 , 代表每个点都连有两条边,可以有重边 不能有自环。
这说明 每个点属于且仅属于一个环。
因为输入只有一个n
应该要往dp递推的方向上去想。
现在开始找递推式。
定义dp[n]表示n个点构成的合法图的方案数。
思考每加入一个新球,如何从已知状态转移。
考虑从前面的n-1个球中选取一些球和新球组成一个环。
特殊考虑只取一个旧球的情况,
这种情况下这个旧球有n-1种方案 剩下的n-2个球组成的合法方案数已经求出。
所以这种情况下 方案数为(n-1)f(n-2)
推广到一般情况
当我们取k个旧球,剩下的球与新球组成环时,旧球的取法有C(n-1,k) ,剩下的旧球与新球组成环的方案数有(n-1-k)!种
但是考虑对称性 需要除以2。 又考虑到只取一个球的时候不需要考虑对称性 ,所以把这种情况单独摘出来考虑。
最后得到 dp[n]的递推式就是
dp[n] = (n-1) dp[n-2] + sigma(x:2->n-3)((n-1)!/(2*x!)dp[x])
但是这个东西有一个讨厌的sigma 我们可以通过相减的方法来消除这个sigma。
#include<iostream> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<cstdio> #include<algorithm> #include<map> #include<set> #define rep(i,e) for(int i=0;i<(e);i++) #define rep1(i,e) for(int i=1;i<=(e);i++) #define repx(i,x,e) for(int i=(x);i<=(e);i++) #define X first #define Y second #define PB push_back #define MP make_pair #define mset(var,val) memset(var,val,sizeof(var)) #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define pd(a) printf("%d ",a) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define IOS ios::sync_with_stdio(false);cin.tie(0) #define lc idx<<1 #define rc idx<<1|1 #define rson mid+1,r,rc #define lson l,mid,lc using namespace std; typedef long long ll; template <class T> void test(T a){cout<<a<<endl;} template <class T,class T2> void test(T a,T2 b){cout<<a<<" "<<b<<endl;} template <class T,class T2,class T3> void test(T a,T2 b,T3 c){cout<<a<<" "<<b<<" "<<c<<endl;} const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fll; const ll mod = 1e9+7; int T; void testcase(){ printf("Case %d: ",++T); } const int MAXN = 1e6+10; const int MAXM = 30; ll dp[MAXN]; int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL ll n,m; dp[1]=0; dp[2]=dp[3]=1; while(cin>>n>>m){ for(ll i=4;i<=n;i++){ dp[i]=((i-1)*dp[i-1]%m + (i-1)*dp[i-2]%m+m-(i-1)*(i-2)/2%m*dp[i-3]%m)%m; } cout<<dp[n]<<endl; } return 0; }