组合数+错排问题
下面给出错排公式:
$D(n)$表示$n$个数错排
考虑$n$放置的位置为$k$,则$k$的取值有$n-1$种取法
考虑$k$是否放置在第$n$个位置,分别可以转化为$n-1$(不放在 $n$ )与$n-2$(放在 $n$ )的错排问题。
因此,递推公式为$D(n)=(n-1)(D(n-1)+D(n-2))$
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#define gc getchar()
#define ll long long
using namespace std;
const int N=1e6+5;
const int mod=1e9+7;
ll p[N],d[N],inv[N];
inline void qr(int &x)
{
x=0;char c=gc;int f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(ll x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
ll pow_mod(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
b>>=1;a=a*a%mod;
}
return ans;
}
int main()
{
//freopen("a.out","w",stdout);
inv[0]=1;p[1]=1;inv[1]=1;for(int i=2;i<=1000000;i++)p[i]=p[i-1]*i%mod;
inv[1000000]=pow_mod(p[1000000],mod-2);
for(int i=999999;i>=2;i--)inv[i]=inv[i+1]*(i+1)%mod;
d[1]=0;for(int i=2;i<=1000000;i++)d[i]=(d[i-1]*i%mod+((i&1)?-1:1)+mod)%mod;
int T;scanf("%d",&T);
while(T--)
{
int n,m;qr(n),qr(m);
//if(m==0){puts("0");continue;}
ll ans=p[n]*inv[m]%mod*inv[n-m]%mod;
if(n-m)ans=ans*d[n-m]%mod;qw(ans);puts("");
}
return 0;
}
最后一次更新于2019-09-28
0 条评论