【组合数学】P4071 [SDOI2016]排列计数

传送门:https://www.luogu.com.cn/problem/P4071

分析

就是从 n 个数中挑 nm 个数,然后求 nm 的错排个数即可。

Dn 表示 n 个数错排的个数,有

错排的通式:Dn=n!(111!+12!13!...+(1)n1n!)
错排递推式:Dn=(n1)(Dn1+Dn2)

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define endl '\n'

const int N=1e6+5, mod=1e9+7;


inline void read(ll &x) {
    int s=0;x=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

ll d[N];

ll fpow(ll x,ll p)
{
    ll res=1;
    for(;p;p>>=1,x=x*x%mod)
        if(p&1)res=res*x%mod;
    return res%mod;
}

ll inv(ll x){
	return fpow(x,mod-2)%mod;
}

ll fac[N];

ll C(ll a, ll b){
	return fac[a]*inv(fac[b])%mod*inv(fac[a-b])%mod;
}

void init(){
	d[1]=0, d[0]=d[2]=1;
	for(int i=3; i<N; i++) d[i]=(i-1)*(d[i-1]+d[i-2])%mod;
	
	fac[0]=1;
	for(int i=1; i<N; i++) fac[i]=fac[i-1]*i%mod;
}


int main(){
	init();
	int T; cin>>T;
	while(T--){
		ll n, m; read(n), read(m);
		cout<<C(n, m)*d[n-m]%mod<<endl;
	}
	return 0;
}
posted @   HinanawiTenshi  阅读(66)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示