4517: [Sdoi2016]排列计数
Description
求有多少种长度为 n 的序列 A,满足以下条件:
1 ~ n 这 n 个数在序列中各出现了一次
若第 i 个数 A[i] 的值为 i,则称 i 是稳定的。序列恰好有 m 个数是稳定的
满足条件的序列可能很多,序列数对 10^9+7 取模。
Solution
答案是:\(C(n,m)*D(n-m)\)
\(D(n)\) 是长度为\(n\)的错排的方案数
\(D(n)=n!*(1-\frac{1}{1!}+\frac{1}{2!}-\frac{1}{3!}+(-1)^n\frac{1}{n!})\)
或者 \(D(n)=(n-1)*(D(n-1)+D(n-2))\)
递推求出来即可
#include<bits/stdc++.h>
using namespace std;
const int N=1000005,mod=1e9+7;
int Fac[N],D[N],T,inv[N],n,m,Inv[N];
inline int C(int a,int b){return 1ll*Fac[a]*Inv[b]%mod*Inv[a-b]%mod;}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
scanf("%d",&T);
Fac[0]=D[0]=Fac[1]=inv[0]=inv[1]=Inv[0]=Inv[1]=1;
for(int i=2;i<N;i++){
Fac[i]=1ll*Fac[i-1]*i%mod;
inv[i]=(-1ll*(mod/i)*inv[mod%i]%mod+mod)%mod;
Inv[i]=1ll*Inv[i-1]*inv[i]%mod;
D[i]=(D[i-1]+(i&1?-1:1)*Inv[i])%mod;
if(D[i]<0)D[i]+=mod;
}
for(int i=0;i<N;i++)D[i]=1ll*D[i]*Fac[i]%mod;
while(T--){
scanf("%d%d",&n,&m);
printf("%lld\n",1ll*D[n-m]*C(n,m)%mod);
}
return 0;
}