HDU - 6114 Chess

版权声明:博客作者为blue bear,严禁他人在未经作者同意下进行商用转载 https://blog.csdn.net/weixin_44354699/article/details/88372965

数论 费马小定理

题面

車是中国象棋中的一种棋子,它能攻击同一行或同一列中没有其他棋子阻隔的棋子。一天,小度在棋盘上摆起了许多車……他想知道,在一共N×M个点的矩形棋盘中摆最多个数的車使其互不攻击的方案数。他经过思考,得出了答案。但他仍不满足,想增加一个条件:对于任何一个車A,如果有其他一个車B在它的上方(車B行号小于車A),那么車A必须在車B的右边(車A列号大于車B)。

现在要问问你,满足要求的方案数是多少。
Input
第一行一个正整数T,表示数据组数。

对于每组数据:一行,两个正整数N和M(N<=1000,M<=1000)。
Output
对于每组数据输出一行,代表方案数模1000000007(1e9+7)。

输入 输出
1
1 1
1

分析

看起来像皇后问题,实则简单很多,是一道组合数学的题,也就是C(max,min),比如5行4列,你肯定最多只能摆4列,而有5行,行数不能相同,所以就是C(5,4)。而这个数很大,题目给出模数是质数。因此可以用费马小定理
我们知道
(a+b)%mod=a%mod+b%mod
(a*b)%mod=a%mod*b%mod
而你发现除法没有这个(不做证明,可以自行找个反例如25/5%3),怎么办?
引入逆元概念,你可以看做是倒数即a/b=a*(1/b)现在是乘了就可以用同余定理。
但是逆元并不是真正的倒数,但是胜似倒数。
于是则有C(n,m)=n! * inv[m!] * inv[(n-m)!]

代码

#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll; 
const ll Mod=1e9+7;     //质数才可 
const ll maxn=1e4+5;
ll jc[maxn];
ll inv[maxn];
ll qpow(ll a,ll b,ll mod){//取模快速幂 
    ll ans=1,base=a%mod;
    while(b){
    	if(b&1) ans=(ans*base)%mod;
        base=(base*base)%mod;
        b>>=1;
	}
    return ans;
}
void init(){//阶乘及逆元 
	jc[0]=1;
	for(int i=1;i<maxn;i++){
		jc[i]=(jc[i-1]*i)%Mod;
	}
	inv[maxn-1]=qpow(jc[maxn-1],Mod-2,Mod);
    for (int i=maxn-2;i>=0;i--){
        inv[i]=(inv[i+1]*(i+1))%Mod;
        //1/n!=n+1*1/(n+1)!
    }
}
ll C(ll n,ll m){//n取m
	int i;
	if(n<m) return 0;
	if(m==1) return n;
	else return( ( jc[n]*inv[m] )%Mod * inv[n-m])%Mod;
}
int main(){
	init();
	int T;
	ll n,m;
	scanf("%d",&T);
	while(T--){
		scanf("%lld%lld",&n,&m);
		printf("%lld\n",C(max(n,m),min(n,m)));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44354699/article/details/88372965