题目传送门:https://www.luogu.org/problemnew/show/P3182
题意:
有一个n*n的矩阵,保证每一行、每一列有且仅有1个障碍。现在你要在非障碍的位置放棋子,并且你每一行每一列只能放一个棋子,求方案数。
思路:
初赛没有复习好,hy讲过。
错排公式(百度百科)。
简单来说,就是对于一个n*n的数列,有n个东西放在一些位置,求n个东西不在原位置的方案数。
递推式:
然后我们发现,我们可将棋子想象成障碍,求每一个障碍不再原位置的方案数。
然后我们更惊讶的发现,这个矩阵是无用的!!!
直接套递推式,在打个高精度即可。
练了练重载运算符。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int a[1000];int l;
node()
{
memset(a,0,sizeof(a));
}
friend node operator +(const node &x,const node &y)
{
node z;
z.l=x.l;
for(int i=1;i<=z.l;i++)
{
z.a[i]+=x.a[i]+y.a[i];
z.a[i+1]+=z.a[i]/10;
z.a[i]%=10;
}
z.l++;
while(!z.a[z.l]&&z.l) z.l--;
return z;
}
friend node operator *(const node &x,const int &y)
{
node z;
z.l=x.l+10;
for(int i=1;i<=z.l;i++)
{
z.a[i]+=x.a[i]*y;
z.a[i+1]+=z.a[i]/10;
z.a[i]%=10;
}
while(!z.a[z.l]&&z.l) z.l--;
return z;
}
} d[300];
int n;
int main()
{
scanf("%d",&n);
d[1].a[1]=0;d[1].l=1;
d[2].a[1]=1;d[2].l=1;
for(int i=3;i<=n;i++)
d[i]=(d[i-1]+d[i-2])*(i-1);
for(int i=d[n].l;i>=1;i--)
printf("%d",d[n].a[i]);
}