1. 程式人生 > >BZOJ4517P4071 [SDOI2016]排列計數

BZOJ4517P4071 [SDOI2016]排列計數

錯排+組合數

不難發現把穩定的m個數除掉後,就是一個錯排問題,錯排的遞推式是D[i]=(i-1)*(d[i-1]+d[i-2])具體證明自己去翻一翻別的部落格,我後續也會寫 但是這m個位置是不固定的,所以我們可以在n個位置裡任意選m個也就是CnmC_n^m,然後在剩下的n-m個位置裡做錯排也就是DnmD_{n-m},然後根據乘法原理總的方案數就是CnmDnmC_n^m*D_{n-m},然後因為涉及到取模,所以要求一個逆元,1e9+7是個大質數,所以直接x1e9+5x^{1e9+5}就行了

程式碼

//By AcerMo
#include<cmath>
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define lli long long int using namespace std; const int M=1000500; const int mod=1e9+7; lli n,m; lli C[M],D[M],N[M]; inline lli read() { lli x=0;char ch=getchar(); while (ch>'9'||ch<'0') ch=getchar
(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } inline void write(int x) { if (x>9) write(x/10); putchar(x%10+'0'); return ; } inline lli fpow(lli a,lli b) { lli ans=1; for (;b;a=(a*a)%mod,b>>=1) if (b&1) ans=(ans*a)%mod; return
ans; } inline void fir() { C[0]=1; for (int i=1;i<M;i++) { C[i]=(C[i-1]*i)%mod; N[i]=fpow(C[i],mod-2); } D[1]=0;D[2]=1;D[3]=2; for (int i=4;i<M;i++) D[i]=(i-1)*(D[i-1]+D[i-2])%mod; return ; } signed main() { int t=read();fir(); while (t--) { n=read();m=read(); if (n-m==1){puts("0");continue;} if (m==n) {puts("1");continue;} if (m==0) {write(D[n]);puts("");continue;} lli ans=(C[n]*N[m])%mod; lli que=(N[n-m]*D[n-m])%mod; write((ans*que)%mod);puts(""); } return 0; }