BZOJ 4517|SDOI 2016|排列计数|错排公式|组合数学

75 篇文章 1 订阅
13 篇文章 0 订阅

求满足恰好m个数字使其元素和位置序号不同的全排列的个数。

对于简单的错排问题,全部数字序号不同的排列数字个数定为 D(n)
长度为N的数列,元素1有n-1种放法,对于剩下的n-1个元素,如果元素1放到了位置k,那么元素k放在1,那么剩下的即为 D(n2) ,否则 D(n1)
求得 D(n)=(n1)[D(n2)+D(n1)]

然后本题即为 CmnD(nm)
预处理出所有的答案输出即可。

忘记把%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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值