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

从 $n$ 个数中选 $m$ 个不错排,那就是说 $n-m$ 个数是错排的. 

用组合数乘一下就好了. 

Code: 

#include <cstdio> 
#include <algorithm>    
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;  
namespace IO
{
    char *p1,*p2,buf[100000];
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd() {int x=0; char c=nc(); while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x;} 
}; 
typedef long long ll;   
const int mod=1000000007,N=1000002;         
ll rev[N],f[N],fac[N],inv[N];         
ll qpow(ll base,ll k) 
{
    ll tmp=1; 
    for(;k;base=base*base%mod,k>>=1) if(k&1) tmp=tmp*base%mod; 
    return tmp; 
}
ll C(int n,int m) { return fac[n]*inv[m]%mod*inv[n-m]%mod; }
int main() 
{ 
    using namespace IO;   
    // setIO("input");  
    int T=rd(),n,m,i,j;   
    f[1]=0,f[0]=f[2]=1; 
    fac[0]=inv[1]=inv[0]=1; 
    for(i=3;i<N;++i)  f[i]=(ll)(i-1)*(f[i-1]+f[i-2])%mod; 
    for(i=1;i<N;++i) fac[i]=fac[i-1]*i%mod,inv[i]=qpow(fac[i],mod-2);            
    for(int cas=1;cas<=T;++cas) 
    {
        n=rd(),m=rd();                         
        printf("%lld\n",m>n?0:C(n,m)*f[n-m]%mod);     
    }
    return 0; 
}

  

posted @ 2019-08-19 18:59  EM-LGH  阅读(112)  评论(0编辑  收藏  举报