[排列组合 错排 逆元] P4071 [SDOI2016]排列计数

Posted 鱼竿钓鱼干

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[排列组合 错排 逆元] P4071 [SDOI2016]排列计数相关的知识,希望对你有一定的参考价值。

[排列组合 错排] P4071 [SDOI2016]排列计数

题目

在这里插入图片描述

思路

已知错排公式 D ( n ) = ( n − 1 ) ( D ( n − 1 ) + D ( n − 2 ) ) D(n)=(n-1)(D(n-1)+D(n-2)) D(n)=(n1)(D(n1)+D(n2))
该题要求恰好有m个位置满足ai=i,也就是说n-m个位置是错排的
那么答案就是 a n s = C n m ∗ D ( n − m ) ans=C_n^m*D(n-m) ans=CnmD(nm)

代码

// Problem: P4071 [SDOI2016]排列计数
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4071
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\\n"
typedef long long LL;
typedef pair<int,int> PII;
//#define MULINPUT
/*DATA & KEY

*/
int T;
const int mod=1e9+7,N=1e6+10;
LL fact[N],infact[N],D[N]={1,0};
LL fp(LL a,LL b){
	LL res=1;
	while(b){
		if(b&1)res=res*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return  res%mod;
}

// 预处理阶乘的余数和阶乘逆元的余数
void solve(int C)
{
	//NEW DATA CLEAN
	
	//NOTE!!!	
	fact[0] = infact[0] = 1;
	for (int i = 1; i < N; i ++ )
	{
	    fact[i] = (LL)fact[i - 1] * i % mod;
	    infact[i] = (LL)infact[i - 1] * fp(i, mod - 2) % mod;
	}
	for(int i=2;i<=N;i++)D[i]=(i-1)*(D[i-1]+D[i-2])%mod;
	cin>>T;
	while(T--){
		int n,m;cin>>n>>m;
		LL ans=fact[n]*infact[m]%mod*infact[n-m]%mod*D[n-m]%mod;
		cout<<ans<<endl;
	}
}

int main()
{
	#ifdef MULINPUT
		scanf("%d",&T);
		for(int i=1;i<=T;i++)solve(i);
	#else
		solve(1);
	#endif
	return 0;
}

以上是关于[排列组合 错排 逆元] P4071 [SDOI2016]排列计数的主要内容,如果未能解决你的问题,请参考以下文章

排列组合(错排)

bzoj4517排列计数 错排+组合

hdu 4535(排列组合之错排公式)

AcWing 230. 排列计数 水题(组合数+错排)打卡

BZOJ4517[Sdoi2016]排列计数 组合数+错排

错排公式