ZOJ 3688

本文详细介绍了如何解决一个组合数学问题,通过结合费马小定理与全排列公式,成功求解了一个涉及系数r的难题。作者通过实例分析,展示了将2*n个位置视为圆周排列的方法,并纠正了现有公式中的错误,最终通过费马小定理求得逆元,解决了问题。

做出这题,小有成就感

本来已打算要用那个禁位的排列公式,可是,问题在于,每个阶乘前的系数r的求法是一个难点。

随便翻了翻那本美国教材《组合数学》,在容斥原理一章的习题里竟有一道类似,虽然并无答案,但他的注意倒是提醒了我。不妨把那2*n个位置看成排成一个圆周的一列,从中选出k个不相邻的数的组合数。不过,经我验证,他上面的那道公式是错的,应该把n改成2*n才对。哈哈,问题就这样解决了。

在计组合数时,不妨使用全排列的公式,又由于100.。。0007是一个质数,所以可以使用费马小定理在处理各个阶乘除法时求得逆元。

解决。

#include <iostream>
#include <cstdio>
#include <algorithm>
#define MOD 1000000007
#define N 200005
using namespace std;

typedef long long LL;

LL f[N];

void initial(){
	f[0]=1;
	for(LL i=1;i<N;i++)
	f[i]=(f[i-1]*i)%MOD;
}

LL quick(LL p,LL r){
	LL ans=1;
	while(r){
		if(r&1)
		ans=(ans*p)%MOD;
		r>>=1;
		p=(p*p)%MOD;
	}
	return ans;
}

int main(){
	initial();
	int n;
	while(scanf("%d",&n)!=EOF){
		if(n<3){
			printf("0\n");
			continue;
		}
		LL ans=f[n];
		int s=2*n;
		for(int i=1;i<=n;i++){
			LL uper=((LL)s*f[s-i-1])%MOD;
			LL down=(f[s-2*i]*f[i])%MOD;
			down=quick(down,MOD-2);
			LL res=(((uper*down)%MOD)*f[n-i])%MOD;
			if(i&1){
				ans=((ans-res)%MOD+MOD)%MOD;
			}
			else ans=((ans+res)%MOD+MOD)%MOD;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

  

转载于:https://www.cnblogs.com/jie-dcai/p/4003276.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值