太菜了,直接上OEIS

然后发现递推式:

于是。。。完了/x

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
int n,m;
int a[N];
int main(){
    while(~scanf("%d%d",&n,&m)){
        a[2]=1,a[3]=1%m,a[4]=6%m;
        for(int i=5;i<=n;++i){
            a[i]=(1LL*(i-1)*(a[i-1]+a[i-2]))%m;
            a[i]=(a[i]-(1LL*(i-1)*(i-2)/2*a[i-3])%m);
            a[i]%=m;
        }
        a[n]=(a[n]+m)%m;
        printf("%d\n",a[n]);
    }
    return 0;
}

还是老老实实推下式子吧。。。

这道题我们最好把矩形看做一个图的邻接矩阵,这样,就很好推了

题目就等价于,每个点有且仅有两条边和其他点连接,但不和自己连接

那么,我们设a[i]表示现在有i个点的情况

假设,我们已经递推出了a[1]-a[i-1]的值,那么,对于新增点i,我们有如下转移:

我们先将新点和以前的一个点先连一条边,然后把它们看做一个整体

有如下讨论:

1.整体相对独立,即两个点之间连两条边

贡献:

2.整体不独立,和剩余的i-2个点组合(整体连两条边相当于两个点分别和其它点连一条边)

贡献:

看了下式子,感觉没问题,但交上去后。。。wa了。。。

为什么?

因为,我们有考虑重复的地方!

因为,我们一开始是选了一个点和新点连边构成一个整体,然后,和其他点讨论。

但,如果整体只和一个点“其他点”连边会怎么样呢?

我们设和新点构成整体的点叫x,“其他点”叫y

那么,“新点和x构整体连y”和“新点和y构整体连x”其实是两个完全一样的情况,但,我们却计算了两次!

所以,我们需要再把"新点和一个点构成整体后只和一个点连边"的情况数减半,即为:

(先从i-1个点选一个点与新点做整体,再选一个点与整体单独相连)(剩下i-3个点自由组合)(方案减半)

然后,就可以了~

(菜鸡是根据答案逆推的,可能比顺推的要简单些qwq)