错排相关
考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。n个元素的错排数记为D(n)
公式:D(n)=(n-1)*[D(n-2)+D(n-1)]
特殊地,D(1)= 0, D(2)= 1.
可递推求解.
简化公式:D(n) = [n!/e+0.5] ,其中e是自然对数的底
推导过程:
对于n个元素,一个元素错排数有(n-1)种——放在不同位置的情况有(n-1)种
假设元素a放于元素b的位置,分以下两种情况
1.元素b放于元素a的位置,a与b的位置确定,则剩余(n-2)个元素错排数为D(n-2)
2.元素b放于其他位置,仅能确定a的位置,剩余(n-1)个元素错排数为D(n-1)
根据乘法原理得:D(n)=(n-1)*[D(n-2)+D(n-1)]
http://codevs.cn/problem/1697/⑨要写信
错排+高精度
重载运算符太麻烦了直接写的函数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
int lena,lenb,lenc,lend,x;
int a[1000010],b[1000010],c[1000010],d[1000010];
void mul(int s)//高精乘
{
memset(d,0,sizeof(d));
int tmp=1;
for(int i=1;i<=lenc;i++)
{
d[tmp]+=s*c[i];
if(d[tmp]>=10)
{
d[tmp+1]+=d[tmp]/10;
d[tmp]%=10;
}
tmp++;
}
lend=tmp;
if(d[lend]==0&&lend>0)
lend--;
}
void add()//高精加
{
lenc=1,x=0;
while(lenc<=lena||lenc<=lenb)
{
c[lenc]=a[lenc]+b[lenc]+x;
x=c[lenc]/10;
c[lenc]%=10;
lenc++;
}
c[lenc]=x;
if(c[lenc]==0&&lenc>0)
lenc--;
}
int main()
{
int n;
scanf("%d",&n);
a[1]=0;
b[1]=1;
lena=lenb=1;
for (int i=3;i<=n;i++)
{
add();
mul(i-1);
for(int i=1;i<=lenb;i++)
a[i]=b[i];
lena=lenb;
for(int i=1;i<=lend;i++)
b[i]=d[i];
lenb=lend;
}
if(n==0)//特判
printf("0");
else if(n==1)
printf("0");
else if(n==2)
printf("1");
else
for(int i=lend;i>=1;i--)
printf("%d",d[i]);
return 0;
}