[组合 错排] BZOJ 4517 [Sdoi2016]排列计数

来源:互联网 发布:淘宝付款失败钱扣了 编辑:程序博客网 时间:2024/06/05 22:41

n个里选m个 然后n-m个里错排

***

错排相关公式

Dn=(n-1)*(Dn-1+Dn-2) D1=0,D2=1

Dn=n*Dn-1+(-1)^(n-2)=n*Dn-1+(-1)^n

Dn=n!(1-1/1!+1/2!-1/3!+……±1/n!)


#include<cstdio>#include<cstdlib>#include<algorithm>#define P 1000000007using namespace std;typedef long long ll; inline char nc(){    static char buf[100000],*p1=buf,*p2=buf;    if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }    return *p1++;} inline void read (ll &x){    char c=nc(),b=1;    for (;!(c>='0' && c<='9');c=nc()) if (c=='-') c=-1;    for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;} const int N=1000000;ll D[N+5];ll fac[N+5],inv[N+5]; inline void Pre(){    D[0]=1; D[1]=0; D[2]=1;    for (int i=3;i<=N;i++)        D[i]=(D[i-1]+D[i-2])%P*(i-1)%P;    fac[0]=1;    for (int i=1;i<=N;i++)        (fac[i]=fac[i-1]*i)%=P;    inv[1]=1;    for (int i=2;i<=N;i++)        (inv[i]=(P-P/i)*inv[P%i])%=P;    inv[0]=1;    for (int i=1;i<=N;i++)        (inv[i]*=inv[i-1])%=P;} inline ll C(ll n,ll m){    return fac[n]*inv[m]%P*inv[n-m]%P;} int main(){freopen("t.in","r",stdin);freopen("t.out","w",stdout);    ll Q,n,m,ans;    Pre();    read(Q);     while (Q--)    {        read(n); read(m);        if (n<m) printf("0\n");        ans=C(n,m)*D[n-m]%P;        printf("%lld\n",ans);    }    return 0;}


0 0