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

本文介绍了一种解决特定离散题目中的错排问题的方法。通过递推公式计算错排数目,并结合组合数学中的组合计算,最终求解出给定条件下错排方案的数量。文章提供了详细的数学推导过程及C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题描述的本身就很离散,所以就相当于选出m个位置,剩下的位置的错排
错排的公式也不是很难推,注意及时利用以前的结果就好了,实在不行根据印象打表找规律


设有n个数  ,n个位置,第一个数一定不能选第一个位置,所以可选的位置就有 n-1个
考虑剩下的n-1个数,一定有一个数可以放在1的位置,那这个数放在1的位置的方案数就等于这个数不放在1的位置+这个数放在1的位置= f(n-1)+f(n-2)
虽然感觉应该是个递归到1的过程,但实际上只用到n-2

码:

#include<iostream>
#include<cstdio>
using namespace std;
#define leaves 1000000007
#define ll long long 
#define N 1000005
ll jc[N],f[N],ni[N],T,n,m,x,y,i;
void exgcd(ll a,ll b)
{
	if(!b)
	{
	x=1;
	y=0;
	return ;	
	}
	exgcd(b,a%b);
	ll t=x;
	x=y;
	y=t-a/b*y;	
}
ll C(ll a,ll b)
{
	return jc[b]*ni[a]%leaves*ni[b-a]%leaves;	
}
int main()
{
f[0]=1;
f[1]=0;
f[2]=1;
ll sx=1000000;
for(i=3;i<=sx;i++)
{
	f[i]=(i-1)*(f[i-1]+f[i-2])%leaves;	
}
jc[0]=1;
for(i=1;i<=sx;i++)
jc[i]=jc[i-1]*i%leaves;
exgcd(jc[sx],leaves);
ni[sx]=x;
for(i=sx-1;i>=0;i--)
ni[i]=ni[i+1]*(i+1)%leaves;
	scanf("%lld",&T);
	while(T--)
	{
	scanf("%lld%lld",&n,&m);
	printf("%lld\n",(C(m,n)*f[n-m]%leaves+leaves)%leaves);			
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值