【BZOJ】4517 [Sdoi2016]排列计数(数学+错排公式)

题目

传送门:QWQ

 

 

分析

$ O(nlogn) $预处理出阶乘和阶乘的逆元,然后求组合数就成了$O(1)$了。

最后再套上错排公式:$ \huge d[i]=(i-1) \times (d[i-1] + d[i-2])$其中$ d[i] $表示把i个数错排的方式数量,其中$d[1]=0,d[2]=1$

 

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9+7;
const int maxn = 1100000;
ll inv[maxn+10], jc[maxn+10], jc_inv[maxn+10], d[maxn+10];
void exgcd(ll a,ll b,ll& x,ll& y) {
    if(!b) {x=1;y=0;return;}
    exgcd(b,a%b,y,x); y-=x*(a/b);
}
ll inverse(ll a) {
    ll x,y;
    exgcd(a,MOD,x,y);
    x = (x+MOD)%MOD;
    return x;
}
void init() {
    jc[0]=1; d[2]=1; d[0]=1; jc_inv[0]=1;
    for(int i=1;i<maxn;i++) {
        jc[i] = (jc[i-1]*ll(i)) % MOD;
        jc_inv[i] = inverse(jc[i]);
        if(i>2) d[i] = ((i-1) *(d[i-1] + d[i-2])) % MOD;
    }
}

ll C(ll n, ll m) {
    return jc[n] * jc_inv[m] % MOD * jc_inv[n-m] % MOD;
}
int main() {
    init();
    int t; scanf("%d",&t);
    while(t--) {
        ll n, m; scanf("%lld%lld",&n,&m);
        ll ans = C(n,m) * d[n-m] % MOD;
        printf("%lld\n",ans);
    }
}

 

 

 

转载于:https://www.cnblogs.com/noblex/p/9741195.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值