[排列组合 错排 逆元] 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;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值