错排

错排问题

考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为Dn。

递推公式:Dn=(n-1)(Dn-1+Dn-2)  n>3, D1 = 0 , D2 = 1;

求大组合数取余(快速幂+逆元费马小定理)

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000005
const int mod = 1e9+7;
typedef long long ll;
ll f[maxn],fi[maxn];
ll qpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans%mod;
}
void F(){
    f[0]=1;
    for(int i=1;i<=maxn;i++){
        f[i]=f[i-1]*i%mod;
    }
}
ll C(ll x,ll y){
    ll ans=f[x]%mod*qpow(f[y]*f[x-y]%mod,mod-2)%mod;
    return ans;
}

题目描述

求有多少种长度为n的序列A,满足以下条件:
1.1~n这n个数在序列中各出现了一次。
2.若第i个数Ai的值为i,则称i是稳定的。序列恰好有m个数是稳定的。
满足条件的序列可能很多,序列数对109+7取模。

输入

第一行一个数T,表示有T组数据。
接下来T行,每行两个整数n,m。

输出

输出T行,每行一个数,表示求出的序列数

样例输入

复制样例数据

5
1 0
1 1
5 2
100 50
10000 5000

样例输出

0
1
20
578028887
60695423

提示

T=500000,n,m≤106 
数据有梯度。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000005
const int mod = 1e9+7;
typedef long long ll;
ll f[maxn],fi[maxn];
ll qpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans%mod;
}
void F(){
    f[0]=1;
    for(int i=1;i<=maxn;i++){
        f[i]=f[i-1]*i%mod;
    }
}
ll C(ll x,ll y){
    ll ans=f[x]%mod*qpow(f[y]*f[x-y]%mod,mod-2)%mod;
    return ans;
}
int main()
{
    int t;
    cin>>t;
    F();
    fi[0]=1;
    fi[1]=0;
    fi[2]=1;
    for(int i=3;i<=maxn-5;i++){
        fi[i]=(i-1)*(fi[i-1]+fi[i-2])%mod;
    }
    while(t--){
        int n,m;
        scanf("%d %d",&n,&m);
        ll ans=C(n,m)*fi[n-m]%mod;
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/skyleafcoder/p/12319514.html