求满足恰好m个数字使其元素和位置序号不同的全排列的个数。
对于简单的错排问题,全部数字序号不同的排列数字个数定为
D(n)
。
长度为N的数列,元素1有n-1种放法,对于剩下的n-1个元素,如果元素1放到了位置k,那么元素k放在1,那么剩下的即为
D(n−2)
,否则
D(n−1)
。
求得
D(n)=(n−1)[D(n−2)+D(n−1)]
然后本题即为
CmnD(n−m)
预处理出所有的答案输出即可。
忘记把%I64d改成%lld OLE了一发。。
#include <cstdio>
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 1e6 + 5;
ll d[N], f[N], inv[N], n[N], m[N];
ll qpow(ll a, ll b) {
ll c = 1;
for (; b; b >>= 1, a = a * a % mod)
if (b & 1) c = c * a % mod;
return c;
}
int main() {
int t, i, p = 0;
scanf("%d", &t);
d[0] = 1; d[1] = 0; d[2] = 1; f[0] = f[1] = inv[0] = inv[1] = 1;
f[2] = 2; inv[2] = qpow(2, mod - 2);
for (i = 1; i <= t; ++i) {
scanf("%d%d", &n[i], &m[i]);
if (n[i] > p) p = n[i];
}
for (i = 3; i <= p; ++i) {
d[i] = (d[i - 1] + d[i - 2]) % mod * (i - 1) % mod;
f[i] = f[i - 1] * i % mod;
inv[i] = qpow(f[i], mod - 2);
}
for (i = 1; i <= t; ++i)
printf("%lld\n", f[n[i]] * inv[n[i] - m[i]] % mod * inv[m[i]] % mod * d[n[i] - m[i]] % mod);
return 0;
}
4517: [Sdoi2016]排列计数
Description
求有多少种长度为 n 的序列 A,满足以下条件:
1 ~ n 这 n 个数在序列中各出现了一次
若第 i 个数 A[i] 的值为 i,则称 i 是稳定的。序列恰好有 m 个数是稳定的
满足条件的序列可能很多,序列数对 10^9+7 取模。
Input
第一行一个数 T,表示有 T 组数据。
接下来 T 行,每行两个整数 n、m。
T=500000,n≤1000000,m≤1000000
Output
输出 T 行,每行一个数,表示求出的序列数
Sample Input
5
1 0
1 1
5 2
100 50
10000 5000
Sample Output
0
1
20
578028887
60695423