错排数
定义
考虑一个有 个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 个元素的错排数记为 。
对于情况较少的排列,可以使用枚举法。
当 时,全排列只有一种,不是错排,。
当 时,全排列有两种,即 和 ,后者是错排,。
当n=3时,全排列有六种,其中只有 和 是错排,。用同样的方法可以知道 。
最小的几个错排数是:。
递推式:
考虑对于一个数 ,放在了第 个位置,那么 这个数就可以放在 位置,或者除了 以为的任意一个位置。
(1) 放在了 位置,那么剩下的 个数的排列方法就是 。
(2) 不放在 位置,那么 就有 个位置可以去,其余的所有元素也都有 个位置可以去,那么就成为了 个元素的错排问题,方案数为 。
而这样的 一共有 个,所以最终的递推式就是:
。
排列计数
求有多少种 到 的排列 ,满足序列恰好有 个位置 ,使得 。
答案对 取模。
,。
思路:
排列中有 个位置在原位置上,那么也就是有 个数不在原位置上,这部分的方案数就是 ,而选取这 个位置的方案数为 ,所以最终的答案为:
。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
const int N=1e6+10;
int fac[N],infac[N],inv[N],n,m,T,d[N];
void init()
{
fac[0]=infac[0]=inv[0]=fac[1]=infac[1]=inv[1]=1;d[1]=0;d[2]=1;
for(int i=2;i<N-1;i++)
{
d[i+1]=1ll*i*(d[i]+d[i-1])%mod;
fac[i]=1ll*i*fac[i-1]%mod;
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
infac[i]=1ll*infac[i-1]*inv[i]%mod;
}
}
int C(int n,int m){return 1ll*fac[n]*infac[m]%mod*infac[n-m]%mod;}
int main()
{
init();
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
if(n==m) puts("1");
else printf("%d\n",(1ll*C(n,m)*d[n-m]%mod+mod)%mod);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律