組合數學+錯排問題【p4071】[SDOI2016]排列計數
阿新 • • 發佈:2018-11-01
列數 out input while tro 理解 mod void script
Description
求有多少種長度為 n 的序列 A,滿足以下條件:
1 ~ n 這 n 個數在序列中各出現了一次
若第 i 個數 A[i] 的值為 i,則稱 i 是穩定的。序列恰好有 m 個數是穩定的
滿足條件的序列可能很多,序列數對 10^9+7109+7 取模。
Input
第一行一個數 T,表示有 T 組數據。
接下來 T 行,每行兩個整數 n、m。
Output
輸出 T 行,每行一個數,表示求出的序列數
組合數+錯排問題。
預處理\(fac[i]\)代表\(i\)的階乘.\(inv[i]\)代表\(i\)的階乘的逆元。
\(f[i]\)代表有\(i\)個數的錯排方案數。
我們的答案就是\(C_n^{m} \times f[n-m]\)
不難理解的解釋.
註意判斷\(n==m\)輸出\(1\)。
代碼
#include<iostream> #include<cstdio> #include<algorithm> #define int long long #define mod 1000000007 #define R register using namespace std; const int gz=1000008; int fac[gz]={1,1},inv[gz],T,f[gz]; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } inline int ksm(R int x,R int y) { R int res=1; for(;y;y>>=1,x=x*x%mod) if(y&1)res=res*x%mod; return res; } inline int C(R int n,R int m) { return (fac[n]%mod*inv[n-m])%mod*(inv[m])%mod; } signed main() { f[2]=1; for(R int i=2;i<=gz;i++)fac[i]=fac[i-1]*i%mod; inv[gz]=ksm(fac[gz],mod-2); for(R int i=gz-1;i>=0;i--)inv[i]=((i+1)*inv[i+1])%mod; for(R int i=3;i<=gz;i++)f[i]=(i-1)*(f[i-2]+f[i-1])%mod; in(T); for(R int n,m;T;T--) { in(n),in(m); if(n==m)puts("1"); else printf("%lld\n",((C(n,m)%mod)*(f[n-m]%mod))%mod); } }
組合數學+錯排問題【p4071】[SDOI2016]排列計數