給出一個序列,而後\(A[i]\)的位置放i則稱這是穩定的,而後剩下的\(n-m\)種則是不穩定的,c++
穩定的那\(m\)個數就是在\(n\)個數中選擇\(m\)個數讓他穩定,
而後剩下的不穩定的就是\(n-m\)個數作錯排的方案數,git
錯排例題ui
這就是一個錯排的板子題,而後咱們按照這個板子題來說錯排的原理,spa
就是\(n\)封信,裝到\(n\)個信封中,都裝錯了.code
咱們先看第一我的,由於第一我的裝錯的話有\(n-1\)種狀況,就長這樣:blog
而後拿出其中的一種來看,若是第二封信選擇了第一個信封那就是後邊的\(n-2\)個數作錯排:get
若是第二個沒有選第一封信,那就至關於對剩下的\(n-1\)個作錯排.it
咱們就很容易獲得一個遞推式(設\(f[i]\) 爲給i個數作錯排的方案數):ast
\[(n - 1) \ast (f[n - 1] + f[n - 2])\]class
邊界條件就是\(n\)爲\(1\)和\(2\)的時候,當\(n\)只有\(1\)的時候只能放到這個信封中,因此方案數爲\(0\),
當\(n\)爲\(2\)的時候只有下圖這一種可能,因此方案數爲\(1\).剩下的遞推可得.
求組合數的話咱們能夠用\(Lucas\)定理來求得.
\(Lucas\)定理:
\[Lucas(n, m) \% mod = \tbinom{n \% mod}{m \% mod} * Lucas(n, m)\]
由於這個題中\(n,m\)太大了,咱們能夠用公式直接求,由於須要\(mod\)一個數,
而後由於公式爲\(\frac {n!} {m!(n - m)!}\) 有除法,由於\(mod\)意義下沒有除法運算,
而後咱們能夠求出\(m!(n - m)!\) 的逆元,讓\(n!\) 乘以\(m!(n - m)!\) 的逆元來求\(mod\)意義下的組合數.
由於\(mod\)的這個數爲質數,咱們能夠直接利用費馬小定理來求逆元.
費馬小定理;
\[a^{p - 1} \equiv 1 \ (mod \ p)\]
因此 \[a \ast a^{p -2} \equiv 1 \ (mod \ p)\]
因此在$mod p \(的狀況下\)a\(的逆元就是\)a ^ {p - 2}$
作的時候咱們能夠先處理出前\(1000000\)的錯排和階乘.
#include <bits/stdc++.h> #define N 1000010 #define M 1010 #define ll long long using namespace std; ll mod = 1e9 + 7; ll t, n, m, f[N], jc[N]; ll read() { ll s = 0, f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar(); return f ? -s : s; } ll q_pow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans = (ans * a) % mod; a = (a * a) % mod; b >>= 1; } return ans; } ll c(ll a, ll b) { return (jc[a] % mod * q_pow(jc[b] * jc[a - b] % mod, mod - 2) % mod) % mod; } ll lucas(ll a, ll b) { if (!b) return 1; else return (lucas(a / mod, b / mod) * c(a % mod, b % mod)) % mod; } int main() { t = read(); f[1] = 0, f[2] = 1, jc[1] = 1, jc[2] = 2; for (ll i = 3; i <= 1000000; i++) f[i] = ((i - 1) * (f[i - 1] + f[i - 2]) % mod) % mod, jc[i] = (jc[i - 1] * i) % mod; while (t--) { n = read(), m = read(); if (n == m) puts("1"); else if (n - m == 1) printf("0\n"); else if (m == 0) printf("%lld\n",f[n]); else { ll ans = (f[n - m] % mod * lucas(n, m)) % mod; printf("%lld\n", ans); } } return 0; }